Prevent overriding of Disposable.dispose

A common mistake made was overriding dispose and not calling super.dispose,
so a TS trick is now used to move it to a readonly property instead of a
member method which prevents it being overridden.
This commit is contained in:
Daniel Imms
2022-10-08 08:27:10 -07:00
parent 34475f24c3
commit ac659cb412
19 changed files with 94 additions and 142 deletions
+5 -7
View File
@@ -9,7 +9,7 @@ import { IBuffer } from 'common/buffer/Types';
import { isMac } from 'common/Platform';
import { TimeBasedDebouncer } from 'browser/TimeBasedDebouncer';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { Disposable } from 'common/Lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { ScreenDprMonitor } from 'browser/ScreenDprMonitor';
import { IRenderService } from 'browser/services/Services';
import { removeElementFromParent } from 'browser/Dom';
@@ -104,12 +104,10 @@ export class AccessibilityManager extends Disposable {
// This shouldn't be needed on modern browsers but is present in case the
// media query that drives the ScreenDprMonitor isn't supported
this.register(addDisposableDomListener(window, 'resize', () => this._refreshRowsDimensions()));
}
public dispose(): void {
super.dispose();
removeElementFromParent(this._accessibilityTreeRoot);
this._rowElements.length = 0;
this.register(toDisposable(() => {
removeElementFromParent(this._accessibilityTreeRoot);
this._rowElements.length = 0;
}));
}
private _onBoundaryFocus(e: FocusEvent, position: BoundaryPosition): void {
+4 -6
View File
@@ -8,7 +8,7 @@ import { IDisposable } from 'common/Types';
import { IMouseService, IRenderService } from './services/Services';
import { IBufferService } from 'common/services/Services';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { Disposable, getDisposeArrayDisposable, disposeArray } from 'common/Lifecycle';
import { Disposable, getDisposeArrayDisposable, disposeArray, toDisposable } from 'common/Lifecycle';
import { addDisposableDomListener } from 'browser/Lifecycle';
export class Linkifier2 extends Disposable implements ILinkifier2 {
@@ -36,11 +36,9 @@ export class Linkifier2 extends Disposable implements ILinkifier2 {
) {
super();
this.register(getDisposeArrayDisposable(this._linkCacheDisposables));
}
public dispose(): void {
super.dispose();
this._lastMouseEvent = undefined;
this.register(toDisposable(() => {
this._lastMouseEvent = undefined;
}));
}
public registerLinkProvider(linkProvider: ILinkProvider): IDisposable {
+4 -6
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { Disposable } from 'common/Lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
export type ScreenDprListener = (newDevicePixelRatio?: number, oldDevicePixelRatio?: number) => void;
@@ -26,6 +26,9 @@ export class ScreenDprMonitor extends Disposable {
constructor(private _parentWindow: Window) {
super();
this._currentDevicePixelRatio = this._parentWindow.devicePixelRatio;
this.register(toDisposable(() => {
this.clearListener();
}));
}
public setListener(listener: ScreenDprListener): void {
@@ -43,11 +46,6 @@ export class ScreenDprMonitor extends Disposable {
this._updateDpr();
}
public dispose(): void {
super.dispose();
this.clearListener();
}
private _updateDpr(): void {
if (!this._outerListener) {
return;
+6 -11
View File
@@ -56,6 +56,7 @@ import { OverviewRulerRenderer } from 'browser/decorations/OverviewRulerRenderer
import { DecorationService } from 'common/services/DecorationService';
import { IDecorationService } from 'common/services/Services';
import { OscLinkProvider } from 'browser/OscLinkProvider';
import { toDisposable } from 'common/Lifecycle';
// Let it work inside Node.js for automated testing purposes.
const document: Document = (typeof window !== 'undefined') ? window.document : null as any;
@@ -184,6 +185,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
// Setup listeners
this.register(this._bufferService.onResize(e => this._afterResize(e.cols, e.rows)));
this.register(toDisposable(() => {
this._customKeyEventHandler = undefined;
this.element?.parentNode?.removeChild(this.element);
}));
}
/**
@@ -235,17 +241,6 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.viewport?.onThemeChange(this._colorManager.colors);
}
public dispose(): void {
if (this._isDisposed) {
return;
}
super.dispose();
this._renderService?.dispose();
this._customKeyEventHandler = undefined;
this.write = () => { };
this.element?.parentNode?.removeChild(this.element);
}
protected _setup(): void {
super._setup();
@@ -5,7 +5,7 @@
import { addDisposableDomListener } from 'browser/Lifecycle';
import { IRenderService } from 'browser/services/Services';
import { Disposable } from 'common/Lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, IDecorationService, IInternalDecoration } from 'common/services/Services';
export class BufferDecorationRenderer extends Disposable {
@@ -39,12 +39,10 @@ export class BufferDecorationRenderer extends Disposable {
}));
this.register(this._decorationService.onDecorationRegistered(() => this._queueRefresh()));
this.register(this._decorationService.onDecorationRemoved(decoration => this._removeDecoration(decoration)));
}
public override dispose(): void {
this._container.remove();
this._decorationElements.clear();
super.dispose();
this.register(toDisposable(() => {
this._container.remove();
this._decorationElements.clear();
}));
}
private _queueRefresh(): void {
@@ -6,7 +6,7 @@
import { ColorZoneStore, IColorZone, IColorZoneStore } from 'browser/decorations/ColorZoneStore';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { ICoreBrowserService, IRenderService } from 'browser/services/Services';
import { Disposable } from 'common/Lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
// Helper objects to avoid excessive calculation and garbage collection during rendering. These are
@@ -68,6 +68,9 @@ export class OverviewRulerRenderer extends Disposable {
this._registerDecorationListeners();
this._registerBufferChangeListeners();
this._registerDimensionChangeListeners();
this.register(toDisposable(() => {
this._canvas?.remove();
}));
}
/**
@@ -120,11 +123,6 @@ export class OverviewRulerRenderer extends Disposable {
this._queueRefresh(true);
}
public override dispose(): void {
this._canvas?.remove();
super.dispose();
}
private _refreshDrawConstants(): void {
// width
const outerWidth = Math.floor(this._canvas.width / 3);
+7 -9
View File
@@ -6,7 +6,7 @@
import { IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/shared/Types';
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from 'browser/renderer/dom/DomRendererRowFactory';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants';
import { Disposable } from 'common/Lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IColorSet, ILinkifierEvent, ILinkifier2 } from 'browser/Types';
import { ICharSizeService, ICoreBrowserService } from 'browser/services/Services';
import { IOptionsService, IBufferService, IInstantiationService } from 'common/services/Services';
@@ -89,16 +89,14 @@ export class DomRenderer extends Disposable implements IRenderer {
this.register(this._linkifier2.onShowLinkUnderline(e => this._onLinkHover(e)));
this.register(this._linkifier2.onHideLinkUnderline(e => this._onLinkLeave(e)));
}
public dispose(): void {
this._element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass);
this.register(toDisposable(() => {
this._element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass);
// Outside influences such as React unmounts may manipulate the DOM before our disposal.
// https://github.com/xtermjs/xterm.js/issues/2960
removeElementFromParent(this._rowContainer, this._selectionContainer, this._themeStyleElement, this._dimensionsStyleElement);
super.dispose();
// Outside influences such as React unmounts may manipulate the DOM before our disposal.
// https://github.com/xtermjs/xterm.js/issues/2960
removeElementFromParent(this._rowContainer, this._selectionContainer, this._themeStyleElement, this._dimensionsStyleElement);
}));
}
private _updateDimensions(): void {
-4
View File
@@ -169,10 +169,6 @@ export class RenderService extends Disposable implements IRenderService {
this._onDimensionsChange.fire(this._renderer.dimensions);
}
public dispose(): void {
super.dispose();
}
public hasRenderer(): boolean {
return !!this._renderer;
}
+4 -4
View File
@@ -15,7 +15,7 @@ import { IBufferRange, ILinkifier2 } from 'browser/Types';
import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services';
import { getCoordsRelativeToElement } from 'browser/input/Mouse';
import { moveToCellSequence } from 'browser/input/MoveToCell';
import { Disposable } from 'common/Lifecycle';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { getRangeLength } from 'common/buffer/BufferRange';
/**
@@ -148,10 +148,10 @@ export class SelectionService extends Disposable implements ISelectionService {
this._model = new SelectionModel(this._bufferService);
this._activeSelectionMode = SelectionMode.NORMAL;
}
public dispose(): void {
this._removeMouseDownListeners();
this.register(toDisposable(() => {
this._removeMouseDownListeners();
}));
}
public reset(): void {