Skip to content

Commit 6205552

Browse files
committed
Fix API facade memory leaks
We need to register/dispose any event created in the facades, otherwise embedders need to dispose of the listeners manually. Fixes #4645
1 parent 0224317 commit 6205552

File tree

3 files changed

+22
-16
lines changed

3 files changed

+22
-16
lines changed

src/browser/public/Terminal.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @license MIT
44
*/
55

6-
import { Terminal as ITerminalApi, IMarker, IDisposable, ILocalizableStrings, ITerminalAddon, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, IModes, IDecorationOptions, IDecoration, IBufferElementProvider } from 'xterm';
6+
import { Terminal as ITerminalApi, IMarker, IDisposable, ILocalizableStrings, ITerminalAddon, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, IModes, IDecorationOptions, IDecoration, IBufferElementProvider, ITerminalInitOnlyOptions } from 'xterm';
77
import { IBufferRange, ITerminal } from 'browser/Types';
88
import { Terminal as TerminalCore } from 'browser/Terminal';
99
import * as Strings from 'browser/LocalizableStrings';
@@ -13,22 +13,25 @@ import { UnicodeApi } from 'common/public/UnicodeApi';
1313
import { AddonManager } from 'common/public/AddonManager';
1414
import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi';
1515
import { ITerminalOptions } from 'common/Types';
16+
import { Disposable } from 'common/Lifecycle';
1617

1718
/**
1819
* The set of options that only have an effect when set in the Terminal constructor.
1920
*/
2021
const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows'];
2122

22-
export class Terminal implements ITerminalApi {
23+
export class Terminal extends Disposable implements ITerminalApi {
2324
private _core: ITerminal;
2425
private _addonManager: AddonManager;
2526
private _parser: IParser | undefined;
2627
private _buffer: BufferNamespaceApi | undefined;
2728
private _publicOptions: Required<ITerminalOptions>;
2829

29-
constructor(options?: ITerminalOptions) {
30-
this._core = new TerminalCore(options);
31-
this._addonManager = new AddonManager();
30+
constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions) {
31+
super();
32+
33+
this._core = this.register(new TerminalCore(options));
34+
this._addonManager = this.register(new AddonManager());
3235

3336
this._publicOptions = { ... this._core.options };
3437
const getter = (propName: string): any => {
@@ -92,7 +95,7 @@ export class Terminal implements ITerminalApi {
9295
public get cols(): number { return this._core.cols; }
9396
public get buffer(): IBufferNamespaceApi {
9497
if (!this._buffer) {
95-
this._buffer = new BufferNamespaceApi(this._core);
98+
this._buffer = this.register(new BufferNamespaceApi(this._core));
9699
}
97100
return this._buffer;
98101
}
@@ -189,8 +192,7 @@ export class Terminal implements ITerminalApi {
189192
this._core.selectLines(start, end);
190193
}
191194
public dispose(): void {
192-
this._addonManager.dispose();
193-
this._core.dispose();
195+
super.dispose();
194196
}
195197
public scrollLines(amount: number): void {
196198
this._verifyIntegers(amount);

src/common/public/BufferNamespaceApi.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ import { IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi } from '
77
import { BufferApiView } from 'common/public/BufferApiView';
88
import { EventEmitter } from 'common/EventEmitter';
99
import { ICoreTerminal } from 'common/Types';
10+
import { Disposable } from 'common/Lifecycle';
1011

11-
export class BufferNamespaceApi implements IBufferNamespaceApi {
12+
export class BufferNamespaceApi extends Disposable implements IBufferNamespaceApi {
1213
private _normal: BufferApiView;
1314
private _alternate: BufferApiView;
1415

15-
private readonly _onBufferChange = new EventEmitter<IBufferApi>();
16+
private readonly _onBufferChange = this.register(new EventEmitter<IBufferApi>());
1617
public readonly onBufferChange = this._onBufferChange.event;
1718

1819
constructor(private _core: ICoreTerminal) {
20+
super();
1921
this._normal = new BufferApiView(this._core.buffers.normal, 'normal');
2022
this._alternate = new BufferApiView(this._core.buffers.alt, 'alternate');
2123
this._core.buffers.onBufferActivate(() => this._onBufferChange.fire(this.active));

src/headless/public/Terminal.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,24 @@ import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITer
1111
import { Terminal as TerminalCore } from 'headless/Terminal';
1212
import { AddonManager } from 'common/public/AddonManager';
1313
import { ITerminalOptions } from 'common/Types';
14+
import { Disposable } from 'common/Lifecycle';
1415
/**
1516
* The set of options that only have an effect when set in the Terminal constructor.
1617
*/
1718
const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows'];
1819

19-
export class Terminal implements ITerminalApi {
20+
export class Terminal extends Disposable implements ITerminalApi {
2021
private _core: TerminalCore;
2122
private _addonManager: AddonManager;
2223
private _parser: IParser | undefined;
2324
private _buffer: BufferNamespaceApi | undefined;
2425
private _publicOptions: Required<ITerminalOptions>;
2526

2627
constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions) {
27-
this._core = new TerminalCore(options);
28-
this._addonManager = new AddonManager();
28+
super();
29+
30+
this._core = this.register(new TerminalCore(options));
31+
this._addonManager = this.register(new AddonManager());
2932

3033
this._publicOptions = { ... this._core.options };
3134
const getter = (propName: string): any => {
@@ -94,7 +97,7 @@ export class Terminal implements ITerminalApi {
9497
public get buffer(): IBufferNamespaceApi {
9598
this._checkProposedApi();
9699
if (!this._buffer) {
97-
this._buffer = new BufferNamespaceApi(this._core);
100+
this._buffer = this.register(new BufferNamespaceApi(this._core));
98101
}
99102
return this._buffer;
100103
}
@@ -144,8 +147,7 @@ export class Terminal implements ITerminalApi {
144147
return this.registerMarker(cursorYOffset);
145148
}
146149
public dispose(): void {
147-
this._addonManager.dispose();
148-
this._core.dispose();
150+
super.dispose();
149151
}
150152
public scrollLines(amount: number): void {
151153
this._verifyIntegers(amount);

0 commit comments

Comments
 (0)