Convert to much simpler model
This commit is contained in:
+3
-2
@@ -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 }) => {
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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,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;
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|||||||
Vendored
+7
-11
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user