Convert to much simpler model

This commit is contained in:
Daniel Imms
2019-04-07 14:53:09 -04:00
parent 49f58f5d25
commit 26a80d0d35
10 changed files with 49 additions and 140 deletions
+3 -2
View File
@@ -88,8 +88,9 @@ function createTerminal(): void {
// Load addons // Load addons
const typedTerm = term as TerminalType; const typedTerm = term as TerminalType;
typedTerm.loadAddon(WebLinksAddon).init(); typedTerm.loadAddon(new WebLinksAddon());
attachAddon = typedTerm.loadAddon(AttachAddon); attachAddon = new AttachAddon();
typedTerm.loadAddon(attachAddon);
window.term = term; // Expose `term` to window for debugging purposes window.term = term; // Expose `term` to window for debugging purposes
term.on('resize', (size: { cols: number, rows: number }) => { term.on('resize', (size: { cols: number, rows: number }) => {
+1
View File
@@ -31,6 +31,7 @@ const clientConfig = {
] ]
}, },
resolve: { resolve: {
modules: [path.resolve(__dirname, '..'), 'node_modules'],
extensions: [ '.tsx', '.ts', '.js' ] extensions: [ '.tsx', '.ts', '.js' ]
}, },
output: { output: {
+2 -2
View File
@@ -42,8 +42,8 @@
"vinyl-source-stream": "^1.1.0", "vinyl-source-stream": "^1.1.0",
"webpack": "^4.17.1", "webpack": "^4.17.1",
"webpack-cli": "^3.1.0", "webpack-cli": "^3.1.0",
"xterm-addon-attach": "0.1.0-beta4", "xterm-addon-attach": "0.1.0-beta7",
"xterm-addon-web-links": "0.1.0-beta3", "xterm-addon-web-links": "0.1.0-beta6",
"zmodem.js": "^0.1.5" "zmodem.js": "^0.1.5"
}, },
"scripts": { "scripts": {
+3 -11
View File
@@ -44,7 +44,7 @@ import { DEFAULT_BELL_SOUND, SoundManager } from './SoundManager';
import { MouseZoneManager } from './ui/MouseZoneManager'; import { MouseZoneManager } from './ui/MouseZoneManager';
import { AccessibilityManager } from './AccessibilityManager'; import { AccessibilityManager } from './AccessibilityManager';
import { ScreenDprMonitor } from './ui/ScreenDprMonitor'; import { ScreenDprMonitor } from './ui/ScreenDprMonitor';
import { ITheme, IMarker, IDisposable, ITerminalAddon, ITerminalAddonConstructor } from 'xterm'; import { ITheme, IMarker, IDisposable, ITerminalAddon } from 'xterm';
import { removeTerminalFromCache } from './renderer/atlas/CharAtlasCache'; import { removeTerminalFromCache } from './renderer/atlas/CharAtlasCache';
import { DomRenderer } from './renderer/dom/DomRenderer'; import { DomRenderer } from './renderer/dom/DomRenderer';
import { IKeyboardEvent } from './common/Types'; import { IKeyboardEvent } from './common/Types';
@@ -1925,16 +1925,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// this.options.bellStyle === 'both'; // this.options.bellStyle === 'both';
} }
public loadAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T { public loadAddon(addon: ITerminalAddon): void {
return this._addonManager.loadAddon(this, addonConstructor); return this._addonManager.loadAddon(this, addon);
}
public disposeAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): void {
this._addonManager.disposeAddon(addonConstructor);
}
public getAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T {
return this._addonManager.getAddon(addonConstructor);
} }
} }
+3 -9
View File
@@ -3,7 +3,7 @@
* @license MIT * @license MIT
*/ */
import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ITerminalAddonConstructor } from 'xterm'; import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon } from 'xterm';
import { ITerminal } from '../Types'; import { ITerminal } from '../Types';
import { Terminal as TerminalCore } from '../Terminal'; import { Terminal as TerminalCore } from '../Terminal';
import * as Strings from '../Strings'; import * as Strings from '../Strings';
@@ -154,14 +154,8 @@ export class Terminal implements ITerminalApi {
public static applyAddon(addon: any): void { public static applyAddon(addon: any): void {
addon.apply(Terminal); addon.apply(Terminal);
} }
public loadAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T { public loadAddon(addon: ITerminalAddon): void {
return this._core.loadAddon(addonConstructor); return this._core.loadAddon(addon);
}
public getAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T {
return this._core.getAddon(addonConstructor);
}
public disposeAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): void {
this._core.disposeAddon(addonConstructor);
} }
public static get strings(): ILocalizableStrings { public static get strings(): ILocalizableStrings {
return Strings; return Strings;
+8 -65
View File
@@ -24,84 +24,27 @@ describe('AddonManager', () => {
it('should call addon constructor', () => { it('should call addon constructor', () => {
let called = false; let called = false;
class Addon implements ITerminalAddon { class Addon implements ITerminalAddon {
constructor(terminal: any) { activate(terminal: any): void {
assert.equal(terminal, 'foo', 'The first constructor arg should be Terminal'); assert.equal(terminal, 'foo', 'The first constructor arg should be Terminal');
called = true; called = true;
} }
dispose(): void { } dispose(): void { }
} }
manager.loadAddon('foo' as any, Addon); manager.loadAddon('foo' as any, new Addon());
assert.equal(called, true); assert.equal(called, true);
}); });
}); });
describe('getAddon', () => {
it('should fetch registered addons', () => {
class BaseAddon implements ITerminalAddon {
constructor() { }
dispose(): void { }
}
class Addon1 extends BaseAddon { }
class Addon2 extends BaseAddon { }
class Addon3 extends BaseAddon { }
const addon1 = manager.loadAddon(null, Addon1);
assert.equal(manager.getAddon(Addon1), addon1);
assert.equal(manager.addons.length, 1);
const addon2 = manager.loadAddon(null, Addon2);
assert.equal(manager.getAddon(Addon1), addon1);
assert.equal(manager.getAddon(Addon2), addon2);
assert.equal(manager.addons.length, 2);
const addon3 = manager.loadAddon(null, Addon3);
assert.equal(manager.getAddon(Addon1), addon1);
assert.equal(manager.getAddon(Addon2), addon2);
assert.equal(manager.getAddon(Addon3), addon3);
assert.equal(manager.addons.length, 3);
});
});
describe('disposeAddon', () => {
it('should dispose the loaded addon and remove it from the loaded list', () => {
let called = 0;
class BaseAddon implements ITerminalAddon {
constructor() { }
dispose(): void {
called++;
}
}
class Addon1 extends BaseAddon { }
class Addon2 extends BaseAddon { }
class Addon3 extends BaseAddon { }
manager.loadAddon(null, Addon1);
manager.loadAddon(null, Addon2);
manager.loadAddon(null, Addon3);
assert.equal(manager.addons.length, 3);
manager.disposeAddon(Addon1);
assert.equal(called, 1);
assert.equal(manager.addons.length, 2);
manager.disposeAddon(Addon2);
assert.equal(called, 2);
assert.equal(manager.addons.length, 1);
manager.disposeAddon(Addon3);
assert.equal(called, 3);
assert.equal(manager.addons.length, 0);
});
});
describe('dispose', () => { describe('dispose', () => {
it('should dispose all loaded addons', () => { it('should dispose all loaded addons', () => {
let called = 0; let called = 0;
class BaseAddon implements ITerminalAddon { class Addon implements ITerminalAddon {
constructor() { } activate(): void {}
dispose(): void { dispose(): void { called++; }
called++;
}
} }
class Addon1 extends BaseAddon { } manager.loadAddon(null, new Addon());
class Addon2 extends BaseAddon { } manager.loadAddon(null, new Addon());
class Addon3 extends BaseAddon { } manager.loadAddon(null, new Addon());
manager.loadAddon(null, Addon1);
manager.loadAddon(null, Addon2);
manager.loadAddon(null, Addon3);
assert.equal(manager.addons.length, 3); assert.equal(manager.addons.length, 3);
manager.dispose(); manager.dispose();
assert.equal(called, 3); assert.equal(called, 3);
+12 -24
View File
@@ -3,12 +3,12 @@
* @license MIT * @license MIT
*/ */
import { ITerminalAddon, ITerminalAddonConstructor, IDisposable, Terminal } from 'xterm'; import { ITerminalAddon, IDisposable, Terminal } from 'xterm';
export interface ILoadedAddon { export interface ILoadedAddon {
ctor: ITerminalAddonConstructor<ITerminalAddon>;
instance: ITerminalAddon; instance: ITerminalAddon;
dispose: () => void; dispose: () => void;
isDisposed: boolean;
} }
export class AddonManager implements IDisposable { export class AddonManager implements IDisposable {
@@ -23,38 +23,25 @@ export class AddonManager implements IDisposable {
} }
} }
public loadAddon<T extends ITerminalAddon>(terminal: Terminal, addonConstructor: ITerminalAddonConstructor<T>): T { public loadAddon(terminal: Terminal, instance: ITerminalAddon): void {
const instance = new addonConstructor(terminal);
const loadedAddon: ILoadedAddon = { const loadedAddon: ILoadedAddon = {
ctor: addonConstructor,
instance, instance,
dispose: instance.dispose dispose: instance.dispose,
isDisposed: false
}; };
this._addons.push(loadedAddon); this._addons.push(loadedAddon);
instance.dispose = () => this._wrappedAddonDispose(loadedAddon); instance.dispose = () => this._wrappedAddonDispose(loadedAddon);
return instance; instance.activate(terminal);
}
public disposeAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): void {
const match = this._addons.find(value => value.ctor === addonConstructor);
if (!match) {
throw new Error('Could not dispose an addon that has not been loaded');
}
match.instance.dispose();
}
public getAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T {
const match = this._addons.find(value => value.ctor === addonConstructor);
if (!match) {
return undefined;
}
return match.instance as T;
} }
private _wrappedAddonDispose(loadedAddon: ILoadedAddon): void { private _wrappedAddonDispose(loadedAddon: ILoadedAddon): void {
if (loadedAddon.isDisposed) {
// Do nothing if already disposed
return;
}
let index = -1; let index = -1;
for (let i = 0; i < this._addons.length; i++) { for (let i = 0; i < this._addons.length; i++) {
if (this._addons[i].ctor === loadedAddon.ctor) { if (this._addons[i] === loadedAddon) {
index = i; index = i;
break; break;
} }
@@ -63,6 +50,7 @@ export class AddonManager implements IDisposable {
throw new Error('Could not dispose an addon that has not been loaded'); throw new Error('Could not dispose an addon that has not been loaded');
} }
loadedAddon.dispose(); loadedAddon.dispose();
loadedAddon.isDisposed = true;
this._addons.splice(index, 1); this._addons.splice(index, 1);
} }
} }
+2 -8
View File
@@ -8,7 +8,7 @@ import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBuff
import { ICircularList, XtermListener } from '../common/Types'; import { ICircularList, XtermListener } from '../common/Types';
import { Buffer } from '../Buffer'; import { Buffer } from '../Buffer';
import * as Browser from '../common/Platform'; import * as Browser from '../common/Platform';
import { ITheme, IDisposable, IMarker, ITerminalAddon, ITerminalAddonConstructor } from 'xterm'; import { ITheme, IDisposable, IMarker, ITerminalAddon } from 'xterm';
import { Terminal } from '../Terminal'; import { Terminal } from '../Terminal';
import { AttributeData } from '../BufferLine'; import { AttributeData } from '../BufferLine';
@@ -20,13 +20,7 @@ export class TestTerminal extends Terminal {
} }
export class MockTerminal implements ITerminal { export class MockTerminal implements ITerminal {
loadAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T { loadAddon(addon: ITerminalAddon): void {
throw new Error('Method not implemented.');
}
disposeAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): void {
throw new Error('Method not implemented.');
}
getAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
markers: IMarker[]; markers: IMarker[];
+7 -11
View File
@@ -772,22 +772,18 @@ declare module 'xterm' {
*/ */
static applyAddon(addon: any): void; static applyAddon(addon: any): void;
loadAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T; /**
disposeAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): void; * Loads an addon into this instance of xterm.js.
getAddon<T extends ITerminalAddon>(addonConstructor: ITerminalAddonConstructor<T>): T; * @param addon The addon to load.
} */
loadAddon(addon: ITerminalAddon): void;
export interface ITerminalAddonConstructor<T extends ITerminalAddon> {
new(terminal: Terminal): T;
} }
export interface ITerminalAddon { export interface ITerminalAddon {
/** /**
* This property declares all addon dependencies that must be intialized * This is called when the addon is activated within xterm.js.
* before this addon can be constructed. For addons with no dependencies
* just don't include this property.
*/ */
// readonly DEPENDENCIES?: ITerminalAddonConstructor<ITerminalAddon>[]; activate(terminal: Terminal): void;
/** /**
* This function includes anything that needs to happen to clean up when * This function includes anything that needs to happen to clean up when
+8 -8
View File
@@ -7122,15 +7122,15 @@ xregexp@4.0.0:
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
xterm-addon-attach@0.1.0-beta4: xterm-addon-attach@0.1.0-beta7:
version "0.1.0-beta4" version "0.1.0-beta7"
resolved "https://registry.yarnpkg.com/xterm-addon-attach/-/xterm-addon-attach-0.1.0-beta4.tgz#546010f66533f22bfad7605345e44ed95d90a1de" resolved "https://registry.yarnpkg.com/xterm-addon-attach/-/xterm-addon-attach-0.1.0-beta7.tgz#787f6cce709611ee08ab731b95a62fa1c0bce6a9"
integrity sha512-HwxNoNS1Fxoo6+MPZJ+5+sMTQHrZEcptL4qstHlaERqxL7ei/lvKMpSRfIo1eRNqxL4vHzYkNWJO7QLATmdalA== integrity sha512-nQr6LcYtpZcyDoHyL/BDIPJcTgL7qlHR/rvm8lSizQysGVT0pSzr5M7SjY3kQHw33U3hTer3c6oZzwjfj4ohOw==
xterm-addon-web-links@0.1.0-beta3: xterm-addon-web-links@0.1.0-beta6:
version "0.1.0-beta3" version "0.1.0-beta6"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta3.tgz#bd2d45d399340bd1b5bbf44850a0be9c91a1451e" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta6.tgz#9b4e862be8928ef455a667745bea479665db6c6b"
integrity sha512-nkgwAYZXS97zL650MTl6RnA/iXYAD0yOVf/28+ZTlLQZJVYH2DP22rhOK0aqO+tWX91WUrvkcqxFCY965fomaQ== integrity sha512-tkVU5wCfBFjXwfOvcbMHoLoMDANztkwSREiKyu2R059kEF+sP67Z33HzxVCXUWFuCmutcx40xR2O0BK68gXZlg==
y18n@^3.2.0, y18n@^3.2.1: y18n@^3.2.0, y18n@^3.2.1:
version "3.2.1" version "3.2.1"