diff --git a/README.md b/README.md index 93e7f262..b9b4c177 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ computational environment for Jupyter, supporting interactive data science and s - [**Kubebox**](https://github.com/astefanutti/kubebox): Terminal console for Kubernetes clusters. - [**Azure Cloud Shell**](https://shell.azure.com): Azure Cloud Shell is a Microsoft-managed admin machine built on Azure, for Azure. - [**atom-xterm**](https://atom.io/packages/atom-xterm): Atom plugin for providing terminals inside your Atom workspace. +- [**rtty**](https://github.com/zhaojh329/rtty): A reverse proxy WebTTY. It is composed of the client and the server. Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list. diff --git a/src/addons/attach/Intefaces.ts b/src/addons/attach/Intefaces.ts new file mode 100644 index 00000000..ab809af9 --- /dev/null +++ b/src/addons/attach/Intefaces.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2018 The xterm.js authors. All rights reserved. + * @license MIT + * + * Implements the attach method, that attaches the terminal to a WebSocket stream. + */ + +import { Terminal } from 'xterm'; + +export interface IAttachAddonTerminal extends Terminal { + __socket?: WebSocket; + __attachSocketBuffer?: string; + + __getMessage?(ev: MessageEvent): void; + __flushBuffer?(): void; + __pushToBuffer?(data: string): void; + __sendData?(data: string): void; +} diff --git a/src/addons/attach/attach.test.ts b/src/addons/attach/attach.test.ts index a13885bb..018cfb31 100644 --- a/src/addons/attach/attach.test.ts +++ b/src/addons/attach/attach.test.ts @@ -12,7 +12,7 @@ class MockTerminal {} describe('attach addon', () => { describe('apply', () => { it('should do register the `attach` and `detach` methods', () => { - attach.apply(MockTerminal); + attach.apply(MockTerminal); assert.equal(typeof (MockTerminal).prototype.attach, 'function'); assert.equal(typeof (MockTerminal).prototype.detach, 'function'); }); diff --git a/src/addons/attach/attach.ts b/src/addons/attach/attach.ts index ba938695..d963a658 100644 --- a/src/addons/attach/attach.ts +++ b/src/addons/attach/attach.ts @@ -5,38 +5,42 @@ * Implements the attach method, that attaches the terminal to a WebSocket stream. */ +/// + +import { Terminal } from 'xterm'; +import { IAttachAddonTerminal } from './Intefaces'; + /** * Attaches the given terminal to the given socket. * - * @param {Terminal} term - The terminal to be attached to the given socket. - * @param {WebSocket} socket - The socket to attach the current terminal. - * @param {boolean} bidirectional - Whether the terminal should send data - * to the socket as well. - * @param {boolean} buffered - Whether the rendering of incoming data - * should happen instantly or at a maximum - * frequency of 1 rendering per 10ms. + * @param term The terminal to be attached to the given socket. + * @param socket The socket to attach the current terminal. + * @param bidirectional Whether the terminal should send data to the socket as well. + * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum + * frequency of 1 rendering per 10ms. */ -export function attach(term: any, socket: WebSocket, bidirectional: boolean, buffered: boolean): void { +export function attach(term: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void { + const addonTerminal = term; bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional; - term.socket = socket; + addonTerminal.__socket = socket; - term._flushBuffer = () => { - term.write(term._attachSocketBuffer); - term._attachSocketBuffer = null; + addonTerminal.__flushBuffer = () => { + addonTerminal.write(addonTerminal.__attachSocketBuffer); + addonTerminal.__attachSocketBuffer = null; }; - term._pushToBuffer = (data: string) => { - if (term._attachSocketBuffer) { - term._attachSocketBuffer += data; + addonTerminal.__pushToBuffer = (data: string) => { + if (addonTerminal.__attachSocketBuffer) { + addonTerminal.__attachSocketBuffer += data; } else { - term._attachSocketBuffer = data; - setTimeout(term._flushBuffer, 10); + addonTerminal.__attachSocketBuffer = data; + setTimeout(addonTerminal.__flushBuffer, 10); } }; let myTextDecoder; - term._getMessage = function(ev: MessageEvent): void { + addonTerminal.__getMessage = function(ev: MessageEvent): void { let str; if (typeof ev.data === 'object') { if (ev.data instanceof ArrayBuffer) { @@ -51,71 +55,68 @@ export function attach(term: any, socket: WebSocket, bidirectional: boolean, buf } if (buffered) { - term._pushToBuffer(str || ev.data); + addonTerminal.__pushToBuffer(str || ev.data); } else { - term.write(str || ev.data); + addonTerminal.write(str || ev.data); } }; - term._sendData = (data: string) => { + addonTerminal.__sendData = (data: string) => { if (socket.readyState !== 1) { return; } socket.send(data); }; - socket.addEventListener('message', term._getMessage); + socket.addEventListener('message', addonTerminal.__getMessage); if (bidirectional) { - term.on('data', term._sendData); + addonTerminal.on('data', addonTerminal.__sendData); } - socket.addEventListener('close', term.detach.bind(term, socket)); - socket.addEventListener('error', term.detach.bind(term, socket)); + socket.addEventListener('close', () => detach(addonTerminal, socket)); + socket.addEventListener('error', () => detach(addonTerminal, socket)); } /** * Detaches the given terminal from the given socket * - * @param {Terminal} term - The terminal to be detached from the given socket. - * @param {WebSocket} socket - The socket from which to detach the current - * terminal. + * @param term The terminal to be detached from the given socket. + * @param socket The socket from which to detach the current terminal. */ -export function detach(term: any, socket: WebSocket): void { - term.off('data', term._sendData); +export function detach(term: Terminal, socket: WebSocket): void { + const addonTerminal = term; + addonTerminal.off('data', addonTerminal.__sendData); - socket = (typeof socket === 'undefined') ? term.socket : socket; + socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket; if (socket) { - socket.removeEventListener('message', term._getMessage); + socket.removeEventListener('message', addonTerminal.__getMessage); } - delete term.socket; + delete addonTerminal.__socket; } -export function apply(terminalConstructor: any): void { +export function apply(terminalConstructor: typeof Terminal): void { /** * Attaches the current terminal to the given socket * - * @param {WebSocket} socket - The socket to attach the current terminal. - * @param {boolean} bidirectional - Whether the terminal should send data - * to the socket as well. - * @param {boolean} buffered - Whether the rendering of incoming data - * should happen instantly or at a maximum - * frequency of 1 rendering per 10ms. + * @param socket The socket to attach the current terminal. + * @param bidirectional Whether the terminal should send data to the socket as well. + * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum + * frequency of 1 rendering per 10ms. */ - terminalConstructor.prototype.attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void { + (terminalConstructor.prototype).attach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void { attach(this, socket, bidirectional, buffered); }; /** * Detaches the current terminal from the given socket. * - * @param {WebSocket} socket - The socket from which to detach the current - * terminal. + * @param socket The socket from which to detach the current terminal. */ - terminalConstructor.prototype.detach = function (socket: WebSocket): void { + (terminalConstructor.prototype).detach = function (socket: WebSocket): void { detach(this, socket); }; } diff --git a/src/addons/fit/fit.test.ts b/src/addons/fit/fit.test.ts index 0dc17963..9a6d89fd 100644 --- a/src/addons/fit/fit.test.ts +++ b/src/addons/fit/fit.test.ts @@ -12,7 +12,7 @@ class MockTerminal {} describe('fit addon', () => { describe('apply', () => { it('should do register the `proposeGeometry` and `fit` methods', () => { - fit.apply(MockTerminal); + fit.apply(MockTerminal); assert.equal(typeof (MockTerminal).prototype.proposeGeometry, 'function'); assert.equal(typeof (MockTerminal).prototype.fit, 'function'); }); diff --git a/src/addons/fit/fit.ts b/src/addons/fit/fit.ts index 63111094..75e854d9 100644 --- a/src/addons/fit/fit.ts +++ b/src/addons/fit/fit.ts @@ -13,12 +13,16 @@ * row and truncate its width with the current number of columns). */ +/// + +import { Terminal } from 'xterm'; + export interface IGeometry { rows: number; cols: number; } -export function proposeGeometry(term: any): IGeometry { +export function proposeGeometry(term: Terminal): IGeometry { if (!term.element.parentElement) { return null; } @@ -31,30 +35,30 @@ export function proposeGeometry(term: any): IGeometry { const availableHeight = parentElementHeight - elementPaddingVer; const availableWidth = parentElementWidth - elementPaddingHor; const geometry = { - cols: Math.floor(availableWidth / term.renderer.dimensions.actualCellWidth), - rows: Math.floor(availableHeight / term.renderer.dimensions.actualCellHeight) + cols: Math.floor(availableWidth / (term).renderer.dimensions.actualCellWidth), + rows: Math.floor(availableHeight / (term).renderer.dimensions.actualCellHeight) }; return geometry; } -export function fit(term: any): void { +export function fit(term: Terminal): void { const geometry = proposeGeometry(term); if (geometry) { // Force a full render if (term.rows !== geometry.rows || term.cols !== geometry.cols) { - term.renderer.clear(); + (term).renderer.clear(); term.resize(geometry.cols, geometry.rows); } } } -export function apply(terminalConstructor: any): void { - terminalConstructor.prototype.proposeGeometry = function (): IGeometry { +export function apply(terminalConstructor: typeof Terminal): void { + (terminalConstructor.prototype).proposeGeometry = function (): IGeometry { return proposeGeometry(this); }; - terminalConstructor.prototype.fit = function (): void { + (terminalConstructor.prototype).fit = function (): void { fit(this); }; } diff --git a/src/addons/fullscreen/fullscreen.test.ts b/src/addons/fullscreen/fullscreen.test.ts index 9326ac4e..bb98bd30 100644 --- a/src/addons/fullscreen/fullscreen.test.ts +++ b/src/addons/fullscreen/fullscreen.test.ts @@ -12,7 +12,7 @@ class MockTerminal {} describe('fullscreen addon', () => { describe('apply', () => { it('should do register the `toggleFullscreen` method', () => { - fullscreen.apply(MockTerminal); + fullscreen.apply(MockTerminal); assert.equal(typeof (MockTerminal).prototype.toggleFullScreen, 'function'); }); }); diff --git a/src/addons/fullscreen/fullscreen.ts b/src/addons/fullscreen/fullscreen.ts index 2e5b72e1..47440667 100644 --- a/src/addons/fullscreen/fullscreen.ts +++ b/src/addons/fullscreen/fullscreen.ts @@ -3,13 +3,17 @@ * @license MIT */ +/// + +import { Terminal } from 'xterm'; + /** * Toggle the given terminal's fullscreen mode. - * @param {Terminal} term - The terminal to toggle full screen mode - * @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false) + * @param term The terminal to toggle full screen mode + * @param fullscreen Toggle fullscreen on (true) or off (false) */ -export function toggleFullScreen(term: any, fullscreen: boolean): void { - let fn; +export function toggleFullScreen(term: Terminal, fullscreen: boolean): void { + let fn: string; if (typeof fullscreen === 'undefined') { fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add'; @@ -22,8 +26,8 @@ export function toggleFullScreen(term: any, fullscreen: boolean): void { term.element.classList[fn]('fullscreen'); } -export function apply(terminalConstructor: any): void { - terminalConstructor.prototype.toggleFullScreen = function (fullscreen: boolean): void { +export function apply(terminalConstructor: typeof Terminal): void { + (terminalConstructor.prototype).toggleFullScreen = function (fullscreen: boolean): void { toggleFullScreen(this, fullscreen); }; } diff --git a/src/addons/search/Interfaces.ts b/src/addons/search/Interfaces.ts new file mode 100644 index 00000000..6faa03e2 --- /dev/null +++ b/src/addons/search/Interfaces.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2018 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Terminal } from 'xterm'; + +export interface ISearchAddonTerminal extends Terminal { + __searchHelper?: ISearchHelper; + + // TODO: Reuse ITerminal from core + buffer: any; + selectionManager: any; +} + +export interface ISearchHelper { + findNext(term: string): boolean; + findPrevious(term: string): boolean; +} diff --git a/src/addons/search/SearchHelper.ts b/src/addons/search/SearchHelper.ts index 5735dd48..dd941682 100644 --- a/src/addons/search/SearchHelper.ts +++ b/src/addons/search/SearchHelper.ts @@ -3,8 +3,7 @@ * @license MIT */ -// import { ITerminal } from '../../Interfaces'; -// import { translateBufferLineToString } from '../../utils/BufferLine'; +import { ISearchHelper, ISearchAddonTerminal } from './Interfaces'; interface ISearchResult { term: string; @@ -15,8 +14,8 @@ interface ISearchResult { /** * A class that knows how to search the terminal and how to display the results. */ -export class SearchHelper { - constructor(private _terminal: any) { +export class SearchHelper implements ISearchHelper { + constructor(private _terminal: ISearchAddonTerminal) { // TODO: Search for multiple instances on 1 line // TODO: Don't use the actual selection, instead use a "find selection" so multiple instances can be highlighted // TODO: Highlight other instances in the viewport @@ -134,7 +133,7 @@ export class SearchHelper { return false; } this._terminal.selectionManager.setSelection(result.col, result.row, result.term.length); - this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp, false); + this._terminal.scrollLines(result.row - this._terminal.buffer.ydisp); return true; } } diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts index 473c78fc..5c0b2b96 100644 --- a/src/addons/search/search.ts +++ b/src/addons/search/search.ts @@ -3,8 +3,11 @@ * @license MIT */ -import { SearchHelper } from './SearchHelper'; +/// +import { SearchHelper } from './SearchHelper'; +import { Terminal } from 'xterm'; +import { ISearchAddonTerminal } from './Interfaces'; /** * Find the next instance of the term, then scroll to and select it. If it @@ -12,11 +15,12 @@ import { SearchHelper } from './SearchHelper'; * @param term Tne search term. * @return Whether a result was found. */ -export function findNext(terminal: any, term: string): boolean { - if (!terminal._searchHelper) { - terminal.searchHelper = new SearchHelper(terminal); +export function findNext(terminal: Terminal, term: string): boolean { + const addonTerminal = terminal; + if (!addonTerminal.__searchHelper) { + addonTerminal.__searchHelper = new SearchHelper(addonTerminal); } - return (terminal.searchHelper).findNext(term); + return addonTerminal.__searchHelper.findNext(term); } /** @@ -25,19 +29,20 @@ export function findNext(terminal: any, term: string): boolean { * @param term Tne search term. * @return Whether a result was found. */ -export function findPrevious(terminal: any, term: string): boolean { - if (!terminal._searchHelper) { - terminal.searchHelper = new SearchHelper(terminal); +export function findPrevious(terminal: Terminal, term: string): boolean { + const addonTerminal = terminal; + if (!addonTerminal.__searchHelper) { + addonTerminal.__searchHelper = new SearchHelper(addonTerminal); } - return (terminal.searchHelper).findPrevious(term); + return addonTerminal.__searchHelper.findPrevious(term); } -export function apply(terminalConstructor: any): void { - terminalConstructor.prototype.findNext = function(term: any): boolean { +export function apply(terminalConstructor: typeof Terminal): void { + (terminalConstructor.prototype).findNext = function(term: string): boolean { return findNext(this, term); }; - terminalConstructor.prototype.findPrevious = function(term: any): boolean { + (terminalConstructor.prototype).findPrevious = function(term: string): boolean { return findPrevious(this, term); }; } diff --git a/src/addons/terminado/Intefaces.ts b/src/addons/terminado/Intefaces.ts new file mode 100644 index 00000000..8f17b0cc --- /dev/null +++ b/src/addons/terminado/Intefaces.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2018 The xterm.js authors. All rights reserved. + * @license MIT + * + * Implements the attach method, that attaches the terminal to a WebSocket stream. + */ + +import { Terminal } from 'xterm'; + +export interface ITerminadoAddonTerminal extends Terminal { + __socket?: WebSocket; + __attachSocketBuffer?: string; + + __getMessage?(ev: MessageEvent): void; + __flushBuffer?(): void; + __pushToBuffer?(data: string): void; + __sendData?(data: string): void; + __setSize?(size: {rows: number, cols: number}): void; +} diff --git a/src/addons/terminado/terminado.test.ts b/src/addons/terminado/terminado.test.ts index e258bd7c..2e4a53c5 100644 --- a/src/addons/terminado/terminado.test.ts +++ b/src/addons/terminado/terminado.test.ts @@ -12,7 +12,7 @@ class MockTerminal {} describe('terminado addon', () => { describe('apply', () => { it('should do register the `terminadoAttach` and `terminadoDetach` methods', () => { - terminado.apply(MockTerminal); + terminado.apply(MockTerminal); assert.equal(typeof (MockTerminal).prototype.terminadoAttach, 'function'); assert.equal(typeof (MockTerminal).prototype.terminadoDetach, 'function'); }); diff --git a/src/addons/terminado/terminado.ts b/src/addons/terminado/terminado.ts index e703198f..d5cf72d1 100644 --- a/src/addons/terminado/terminado.ts +++ b/src/addons/terminado/terminado.ts @@ -6,106 +6,107 @@ * WebSocket stream. */ +/// + +import { Terminal } from 'xterm'; +import { ITerminadoAddonTerminal } from './Intefaces'; + /** * Attaches the given terminal to the given socket. * - * @param {Terminal} term - The terminal to be attached to the given socket. - * @param {WebSocket} socket - The socket to attach the current terminal. - * @param {boolean} bidirectional - Whether the terminal should send data - * to the socket as well. - * @param {boolean} buffered - Whether the rendering of incoming data - * should happen instantly or at a maximum - * frequency of 1 rendering per 10ms. + * @param term The terminal to be attached to the given socket. + * @param socket The socket to attach the current terminal. + * @param bidirectional Whether the terminal should send data to the socket as well. + * @param buffered Whether the rendering of incoming data should happen instantly or at a maximum + * frequency of 1 rendering per 10ms. */ -export function terminadoAttach(term: any, socket: WebSocket, bidirectional: boolean, buffered: boolean): void { +export function terminadoAttach(term: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void { + const addonTerminal = term; bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional; - term.socket = socket; + addonTerminal.__socket = socket; - term._flushBuffer = () => { - term.write(term._attachSocketBuffer); - term._attachSocketBuffer = null; + addonTerminal.__flushBuffer = () => { + addonTerminal.write(addonTerminal.__attachSocketBuffer); + addonTerminal.__attachSocketBuffer = null; }; - term._pushToBuffer = (data) => { - if (term._attachSocketBuffer) { - term._attachSocketBuffer += data; + addonTerminal.__pushToBuffer = (data: string) => { + if (addonTerminal.__attachSocketBuffer) { + addonTerminal.__attachSocketBuffer += data; } else { - term._attachSocketBuffer = data; - setTimeout(term._flushBuffer, 10); + addonTerminal.__attachSocketBuffer = data; + setTimeout(addonTerminal.__flushBuffer, 10); } }; - term._getMessage = (ev: MessageEvent) => { + addonTerminal.__getMessage = (ev: MessageEvent) => { const data = JSON.parse(ev.data); if (data[0] === 'stdout') { if (buffered) { - term._pushToBuffer(data[1]); + addonTerminal.__pushToBuffer(data[1]); } else { - term.write(data[1]); + addonTerminal.write(data[1]); } } }; - term._sendData = (data: string) => { + addonTerminal.__sendData = (data: string) => { socket.send(JSON.stringify(['stdin', data])); }; - term._setSize = (size: {rows: number, cols: number}) => { + addonTerminal.__setSize = (size: {rows: number, cols: number}) => { socket.send(JSON.stringify(['set_size', size.rows, size.cols])); }; - socket.addEventListener('message', term._getMessage); + socket.addEventListener('message', addonTerminal.__getMessage); if (bidirectional) { - term.on('data', term._sendData); + addonTerminal.on('data', addonTerminal.__sendData); } - term.on('resize', term._setSize); + addonTerminal.on('resize', addonTerminal.__setSize); - socket.addEventListener('close', term.terminadoDetach.bind(term, socket)); - socket.addEventListener('error', term.terminadoDetach.bind(term, socket)); + socket.addEventListener('close', () => terminadoDetach(addonTerminal, socket)); + socket.addEventListener('error', () => terminadoDetach(addonTerminal, socket)); } /** * Detaches the given terminal from the given socket * - * @param {Xterm} term - The terminal to be detached from the given socket. - * @param {WebSocket} socket - The socket from which to detach the current - * terminal. + * @param term The terminal to be detached from the given socket. + * @param socket The socket from which to detach the current terminal. */ -export function terminadoDetach(term: any, socket: WebSocket): void { - term.off('data', term._sendData); +export function terminadoDetach(term: Terminal, socket: WebSocket): void { + const addonTerminal = term; + addonTerminal.off('data', addonTerminal.__sendData); - socket = (typeof socket === 'undefined') ? term.socket : socket; + socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket; if (socket) { - socket.removeEventListener('message', term._getMessage); + socket.removeEventListener('message', addonTerminal.__getMessage); } - delete term.socket; + delete addonTerminal.__socket; } -export function apply(terminalConstructor: any): void { +export function apply(terminalConstructor: typeof Terminal): void { /** * Attaches the current terminal to the given socket * - * @param {WebSocket} socket - The socket to attach the current terminal. - * @param {boolean} bidirectional - Whether the terminal should send data - * to the socket as well. - * @param {boolean} buffered - Whether the rendering of incoming data - * should happen instantly or at a maximum - * frequency of 1 rendering per 10ms. + * @param socket - The socket to attach the current terminal. + * @param bidirectional - Whether the terminal should send data to the socket as well. + * @param buffered - Whether the rendering of incoming data should happen instantly or at a + * maximum frequency of 1 rendering per 10ms. */ - terminalConstructor.prototype.terminadoAttach = function(socket: WebSocket, bidirectional: boolean, buffered: boolean): void { + (terminalConstructor.prototype).terminadoAttach = function (socket: WebSocket, bidirectional: boolean, buffered: boolean): void { return terminadoAttach(this, socket, bidirectional, buffered); }; /** * Detaches the current terminal from the given socket. * - * @param {WebSocket} socket - The socket from which to detach the current - * terminal. + * @param socket The socket from which to detach the current terminal. */ - terminalConstructor.prototype.terminadoDetach = function(socket: WebSocket): void { + (terminalConstructor.prototype).terminadoDetach = function (socket: WebSocket): void { return terminadoDetach(this, socket); }; } diff --git a/src/addons/winptyCompat/Interfaces.ts b/src/addons/winptyCompat/Interfaces.ts new file mode 100644 index 00000000..8e02c64b --- /dev/null +++ b/src/addons/winptyCompat/Interfaces.ts @@ -0,0 +1,10 @@ +/** + * Copyright (c) 2018 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Terminal } from 'xterm'; + +export interface IWinptyCompatAddonTerminal extends Terminal { + buffer: any; +} diff --git a/src/addons/winptyCompat/winptyCompat.test.ts b/src/addons/winptyCompat/winptyCompat.test.ts index 73761fc9..0c9269ed 100644 --- a/src/addons/winptyCompat/winptyCompat.test.ts +++ b/src/addons/winptyCompat/winptyCompat.test.ts @@ -12,7 +12,7 @@ class MockTerminal {} describe('winptyCompat addon', () => { describe('apply', () => { it('should do register the `winptyCompatInit` method', () => { - winptyCompat.apply(MockTerminal); + winptyCompat.apply(MockTerminal); assert.equal(typeof (MockTerminal).prototype.winptyCompatInit, 'function'); }); }); diff --git a/src/addons/winptyCompat/winptyCompat.ts b/src/addons/winptyCompat/winptyCompat.ts index b594355b..61524e12 100644 --- a/src/addons/winptyCompat/winptyCompat.ts +++ b/src/addons/winptyCompat/winptyCompat.ts @@ -3,36 +3,43 @@ * @license MIT */ -export function winptyCompatInit(terminal: any): void { - // Don't do anything when the platform is not Windows - const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0; - if (!isWindows) { - return; +/// + +import { Terminal } from 'xterm'; +import { IWinptyCompatAddonTerminal } from './Interfaces'; + +export function winptyCompatInit(terminal: Terminal): void { + const addonTerminal = terminal; + + // Don't do anything when the platform is not Windows + const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0; + if (!isWindows) { + return; + } + + // Winpty does not support wraparound mode which means that lines will never + // be marked as wrapped. This causes issues for things like copying a line + // retaining the wrapped new line characters or if consumers are listening + // in on the data stream. + // + // The workaround for this is to listen to every incoming line feed and mark + // the line as wrapped if the last character in the previous line is not a + // space. This is certainly not without its problems, but generally on + // Windows when text reaches the end of the terminal it's likely going to be + // wrapped. + addonTerminal.on('linefeed', () => { + const line = addonTerminal.buffer.lines.get(addonTerminal.buffer.ybase + addonTerminal.buffer.y - 1); + const lastChar = line[addonTerminal.cols - 1]; + + if (lastChar[3] !== 32 /* ' ' */) { + const nextLine = addonTerminal.buffer.lines.get(addonTerminal.buffer.ybase + addonTerminal.buffer.y); + (nextLine).isWrapped = true; } - - // Winpty does not support wraparound mode which means that lines will never - // be marked as wrapped. This causes issues for things like copying a line - // retaining the wrapped new line characters or if consumers are listening - // in on the data stream. - // - // The workaround for this is to listen to every incoming line feed and mark - // the line as wrapped if the last character in the previous line is not a - // space. This is certainly not without its problems, but generally on - // Windows when text reaches the end of the terminal it's likely going to be - // wrapped. - terminal.on('linefeed', () => { - const line = terminal.buffer.lines.get(terminal.buffer.ybase + terminal.buffer.y - 1); - const lastChar = line[terminal.cols - 1]; - - if (lastChar[3] !== 32 /* ' ' */) { - const nextLine = terminal.buffer.lines.get(terminal.buffer.ybase + terminal.buffer.y); - (nextLine).isWrapped = true; - } - }); + }); } -export function apply(terminalConstructor: any): void { - terminalConstructor.prototype.winptyCompatInit = function(): void { +export function apply(terminalConstructor: typeof Terminal): void { + (terminalConstructor.prototype).winptyCompatInit = function (): void { winptyCompatInit(this); }; } diff --git a/src/addons/zmodem/zmodem.test.ts b/src/addons/zmodem/zmodem.test.ts index 7646b7cc..682e62c8 100644 --- a/src/addons/zmodem/zmodem.test.ts +++ b/src/addons/zmodem/zmodem.test.ts @@ -12,7 +12,7 @@ class MockTerminal {} describe('zmodem addon', () => { describe('apply', () => { it('should do register the `zmodemAttach` method and `zmodemBrowser` attribute', () => { - zmodem.apply(MockTerminal); + zmodem.apply(MockTerminal); assert.equal(typeof (MockTerminal).prototype.zmodemAttach, 'function'); assert.equal(typeof (MockTerminal).prototype.zmodemBrowser, 'object'); }); diff --git a/src/addons/zmodem/zmodem.ts b/src/addons/zmodem/zmodem.ts index 4713f111..e8a7824d 100644 --- a/src/addons/zmodem/zmodem.ts +++ b/src/addons/zmodem/zmodem.ts @@ -1,3 +1,12 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +/// + +import { Terminal } from 'xterm'; + /** * * Allow xterm.js to handle ZMODEM uploads and downloads. @@ -33,7 +42,7 @@ export interface IZModemOptions { noTerminalWriteOutsideSession?: boolean; } -export function zmodemAttach(term: any, ws: WebSocket, opts: IZModemOptions = {}): void { +export function zmodemAttach(term: Terminal, ws: WebSocket, opts: IZModemOptions = {}): void { const senderFunc = (octets: ArrayLike) => ws.send(new Uint8Array(octets)); let zsentry; @@ -51,8 +60,8 @@ export function zmodemAttach(term: any, ws: WebSocket, opts: IZModemOptions = {} } }, sender: senderFunc, - on_retract: () => term.emit('zmodemRetract'), - on_detect: (detection: any) => term.emit('zmodemDetect', detection) + on_retract: () => (term).emit('zmodemRetract'), + on_detect: (detection: any) => (term).emit('zmodemDetect', detection) }); function handleWSMessage(evt: MessageEvent): void { @@ -75,9 +84,9 @@ export function zmodemAttach(term: any, ws: WebSocket, opts: IZModemOptions = {} ws.addEventListener('message', handleWSMessage); } -export function apply(terminalConstructor: any): void { +export function apply(terminalConstructor: typeof Terminal): void { zmodem = (typeof window === 'object') ? (window).ZModem : {Browser: null}; // Nullify browser for tests - terminalConstructor.prototype.zmodemAttach = zmodemAttach.bind(this, this); - terminalConstructor.prototype.zmodemBrowser = zmodem.Browser; + (terminalConstructor.prototype).zmodemAttach = zmodemAttach.bind(this, this); + (terminalConstructor.prototype).zmodemBrowser = zmodem.Browser; }