diff --git a/.npmignore b/.npmignore index 1b9f6b6286..856b84ab3b 100644 --- a/.npmignore +++ b/.npmignore @@ -50,3 +50,4 @@ fixtures/ demo/ .devcontainer/ out/ +addons/ diff --git a/addons/@xtermjs/addon-attach/.gitignore b/addons/@xtermjs/addon-attach/.gitignore new file mode 100644 index 0000000000..3063f07d55 --- /dev/null +++ b/addons/@xtermjs/addon-attach/.gitignore @@ -0,0 +1,2 @@ +lib +node_modules diff --git a/addons/@xtermjs/addon-attach/.npmignore b/addons/@xtermjs/addon-attach/.npmignore new file mode 100644 index 0000000000..e8fc8237a1 --- /dev/null +++ b/addons/@xtermjs/addon-attach/.npmignore @@ -0,0 +1,4 @@ +**/*.api.js +**/*.api.ts +tsconfig.json +.yarnrc diff --git a/addons/@xtermjs/addon-attach/LICENSE b/addons/@xtermjs/addon-attach/LICENSE new file mode 100644 index 0000000000..e597698cc6 --- /dev/null +++ b/addons/@xtermjs/addon-attach/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/addons/@xtermjs/addon-attach/package.json b/addons/@xtermjs/addon-attach/package.json new file mode 100644 index 0000000000..84664474f2 --- /dev/null +++ b/addons/@xtermjs/addon-attach/package.json @@ -0,0 +1,17 @@ +{ + "name": "@xtermjs/addon-attach", + "version": "0.1.0-beta8", + "author": { + "name": "The xterm.js authors", + "url": "https://xtermjs.org/" + }, + "main": "lib/AttachAddon.js", + "types": "typings/attach.d.ts", + "license": "MIT", + "scripts": { + "prepublishOnly": "../../../node_modules/.bin/tsc -p src" + }, + "peerDependencies": { + "xterm": "^3.14.0" + } +} diff --git a/addons/@xtermjs/addon-attach/src/AttachAddon.api.ts b/addons/@xtermjs/addon-attach/src/AttachAddon.api.ts new file mode 100644 index 0000000000..39a6f73ab9 --- /dev/null +++ b/addons/@xtermjs/addon-attach/src/AttachAddon.api.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import * as puppeteer from 'puppeteer'; +import { assert } from 'chai'; +import { ITerminalOptions } from 'xterm'; +import WebSocket = require('ws'); + +const APP = 'http://127.0.0.1:3000/test'; + +let browser: puppeteer.Browser; +let page: puppeteer.Page; +const width = 800; +const height = 600; + +describe('AttachAddon', () => { + before(async function(): Promise { + this.timeout(10000); + browser = await puppeteer.launch({ + headless: process.argv.indexOf('--headless') !== -1, + slowMo: 80, + args: [`--window-size=${width},${height}`] + }); + page = (await browser.pages())[0]; + await page.setViewport({ width, height }); + }); + + after(async () => { + await browser.close(); + }); + + beforeEach(async function(): Promise { + this.timeout(5000); + await page.goto(APP); + }); + + it('string', async function(): Promise { + this.timeout(20000); + await openTerminal({ rendererType: 'dom' }); + const port = 8080; + const server = new WebSocket.Server({ port }); + server.on('connection', socket => socket.send('foo')); + await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`); + assert.equal(await page.evaluate(`window.term.buffer.getLine(0).translateToString(true)`), 'foo'); + server.close(); + }); + + it('utf8', async function(): Promise { + this.timeout(20000); + await openTerminal({ rendererType: 'dom' }); + const port = 8080; + const server = new WebSocket.Server({ port }); + const data = new Uint8Array([102, 111, 111]); + server.on('connection', socket => socket.send(data)); + await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}'), { inputUtf8: true }))`); + assert.equal(await page.evaluate(`window.term.buffer.getLine(0).translateToString(true)`), 'foo'); + server.close(); + }); +}); + +async function openTerminal(options: ITerminalOptions = {}): Promise { + await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`); + await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`); + if (options.rendererType === 'dom') { + await page.waitForSelector('.xterm-rows'); + } else { + await page.waitForSelector('.xterm-text-layer'); + } +} diff --git a/addons/@xtermjs/addon-attach/src/AttachAddon.ts b/addons/@xtermjs/addon-attach/src/AttachAddon.ts new file mode 100644 index 0000000000..9dc45ecbd3 --- /dev/null +++ b/addons/@xtermjs/addon-attach/src/AttachAddon.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2014, 2019 The xterm.js authors. All rights reserved. + * @license MIT + * + * Implements the attach method, that attaches the terminal to a WebSocket stream. + */ + +import { Terminal, IDisposable, ITerminalAddon } from 'xterm'; + +interface IAttachOptions { + bidirectional?: boolean; + inputUtf8?: boolean; +} + +export class AttachAddon implements ITerminalAddon { + private _socket: WebSocket; + private _bidirectional: boolean; + private _utf8: boolean; + private _disposables: IDisposable[] = []; + + constructor(socket: WebSocket, options?: IAttachOptions) { + this._socket = socket; + // always set binary type to arraybuffer, we do not handle blobs + this._socket.binaryType = 'arraybuffer'; + this._bidirectional = (options && options.bidirectional === false) ? false : true; + this._utf8 = !!(options && options.inputUtf8); + } + + public activate(terminal: Terminal): void { + if (this._utf8) { + this._disposables.push(addSocketListener(this._socket, 'message', + (ev: MessageEvent | Event | CloseEvent) => terminal.writeUtf8(new Uint8Array((ev as any).data as ArrayBuffer)))); + } else { + this._disposables.push(addSocketListener(this._socket, 'message', + (ev: MessageEvent | Event | CloseEvent) => terminal.write((ev as any).data as string))); + } + + if (this._bidirectional) { + this._disposables.push(terminal.onData(data => this._sendData(data))); + } + + this._disposables.push(addSocketListener(this._socket, 'close', () => this.dispose())); + this._disposables.push(addSocketListener(this._socket, 'error', () => this.dispose())); + } + + public dispose(): void { + this._disposables.forEach(d => d.dispose()); + } + + private _sendData(data: string): void { + // TODO: do something better than just swallowing + // the data if the socket is not in a working condition + if (this._socket.readyState !== 1) { + return; + } + this._socket.send(data); + } +} + +function addSocketListener(socket: WebSocket, type: string, handler: (this: WebSocket, ev: MessageEvent | Event | CloseEvent) => any): IDisposable { + socket.addEventListener(type, handler); + return { + dispose: () => { + if (!handler) { + // Already disposed + return; + } + socket.removeEventListener(type, handler); + } + }; +} diff --git a/addons/@xtermjs/addon-attach/src/tsconfig.json b/addons/@xtermjs/addon-attach/src/tsconfig.json new file mode 100644 index 0000000000..d7338b28d7 --- /dev/null +++ b/addons/@xtermjs/addon-attach/src/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es2015", + "lib": [ + "dom", + "es2015" + ], + "rootDir": ".", + "outDir": "../lib", + "sourceMap": true, + "removeComments": true, + "strict": true + }, + "include": [ + "./**/*", + "../../../../typings/xterm.d.ts" + ] +} diff --git a/addons/@xtermjs/addon-attach/typings/attach.d.ts b/addons/@xtermjs/addon-attach/typings/attach.d.ts new file mode 100644 index 0000000000..90538bf6b6 --- /dev/null +++ b/addons/@xtermjs/addon-attach/typings/attach.d.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Terminal, ILinkMatcherOptions, ITerminalAddon } from 'xterm'; + +declare module '@xtermjs/addon-attach' { + export interface IAttachOptions { + /** + * Whether input should be written to the backend. Defaults to `true`. + */ + bidirectional?: boolean; + + /** + * Whether to use UTF8 binary transport for incoming messages. Defaults to `false`. + * Note: This must be in line with the server side of the websocket. + * Always send string messages from the backend if this options is false, + * otherwise always binary UTF8 data. + */ + inputUtf8?: boolean; + } + + export class AttachAddon implements ITerminalAddon { + constructor(socket: WebSocket, options?: IAttachOptions); + public activate(terminal: Terminal): void; + public dispose(): void; + } +} diff --git a/addons/@xtermjs/addon-fit/.gitignore b/addons/@xtermjs/addon-fit/.gitignore new file mode 100644 index 0000000000..3063f07d55 --- /dev/null +++ b/addons/@xtermjs/addon-fit/.gitignore @@ -0,0 +1,2 @@ +lib +node_modules diff --git a/addons/@xtermjs/addon-fit/.npmignore b/addons/@xtermjs/addon-fit/.npmignore new file mode 100644 index 0000000000..e8fc8237a1 --- /dev/null +++ b/addons/@xtermjs/addon-fit/.npmignore @@ -0,0 +1,4 @@ +**/*.api.js +**/*.api.ts +tsconfig.json +.yarnrc diff --git a/addons/@xtermjs/addon-fit/LICENSE b/addons/@xtermjs/addon-fit/LICENSE new file mode 100644 index 0000000000..8f17892587 --- /dev/null +++ b/addons/@xtermjs/addon-fit/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019, The xterm.js authors (https://github.com/xtermjs/xterm.js) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/addons/@xtermjs/addon-fit/package.json b/addons/@xtermjs/addon-fit/package.json new file mode 100644 index 0000000000..a9cedf142d --- /dev/null +++ b/addons/@xtermjs/addon-fit/package.json @@ -0,0 +1,17 @@ +{ + "name": "@xtermjs/addon-fit", + "version": "0.1.0-beta7", + "author": { + "name": "The xterm.js authors", + "url": "https://xtermjs.org/" + }, + "main": "lib/FitAddon.js", + "types": "typings/fit.d.ts", + "license": "MIT", + "scripts": { + "prepublishOnly": "../../../node_modules/.bin/tsc -p src" + }, + "peerDependencies": { + "xterm": "^3.14.0" + } +} diff --git a/addons/@xtermjs/addon-fit/src/FitAddon.ts b/addons/@xtermjs/addon-fit/src/FitAddon.ts new file mode 100644 index 0000000000..f2c3714184 --- /dev/null +++ b/addons/@xtermjs/addon-fit/src/FitAddon.ts @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Terminal, ITerminalAddon } from 'xterm'; + +interface ITerminalDimensions { + /** + * The number of rows in the terminal. + */ + rows: number; + + /** + * The number of columns in the terminal. + */ + cols: number; +} + +export class FitAddon implements ITerminalAddon { + private _terminal: Terminal | undefined; + + constructor() {} + + public activate(terminal: Terminal): void { + this._terminal = terminal; + } + + public dispose(): void {} + + public fit(): void { + const dims = this.proposeDimensions(); + if (!dims || !this._terminal) { + return; + } + + // TODO: Remove reliance on private API + const core = (this._terminal)._core; + + // Force a full render + if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) { + core._renderCoordinator.clear(); + this._terminal.resize(dims.cols, dims.rows); + } + } + + public proposeDimensions(): ITerminalDimensions | undefined { + if (!this._terminal) { + return undefined; + } + + if (!this._terminal.element.parentElement) { + return undefined; + } + + // TODO: Remove reliance on private API + const core = (this._terminal)._core; + + const parentElementStyle = window.getComputedStyle(this._terminal.element.parentElement); + const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')); + const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width'))); + const elementStyle = window.getComputedStyle(this._terminal.element); + const elementPadding = { + top: parseInt(elementStyle.getPropertyValue('padding-top')), + bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')), + right: parseInt(elementStyle.getPropertyValue('padding-right')), + left: parseInt(elementStyle.getPropertyValue('padding-left')) + }; + const elementPaddingVer = elementPadding.top + elementPadding.bottom; + const elementPaddingHor = elementPadding.right + elementPadding.left; + const availableHeight = parentElementHeight - elementPaddingVer; + const availableWidth = parentElementWidth - elementPaddingHor - core.viewport.scrollBarWidth; + const geometry = { + cols: Math.floor(availableWidth / core._renderCoordinator.dimensions.actualCellWidth), + rows: Math.floor(availableHeight / core._renderCoordinator.dimensions.actualCellHeight) + }; + return geometry; + } +} diff --git a/src/addons/attach/tsconfig.json b/addons/@xtermjs/addon-fit/src/tsconfig.json similarity index 60% rename from src/addons/attach/tsconfig.json rename to addons/@xtermjs/addon-fit/src/tsconfig.json index 2f39102cab..cff0857be8 100644 --- a/src/addons/attach/tsconfig.json +++ b/addons/@xtermjs/addon-fit/src/tsconfig.json @@ -4,16 +4,16 @@ "target": "es5", "lib": [ "dom", - "es6", + "es2015" ], "rootDir": ".", - "outDir": "../../../lib/addons/attach/", + "outDir": "../lib", "sourceMap": true, "removeComments": true, - "declaration": true + "strict": true }, "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" + "./**/*", + "../../../../typings/xterm.d.ts" ] } diff --git a/addons/@xtermjs/addon-fit/typings/fit.d.ts b/addons/@xtermjs/addon-fit/typings/fit.d.ts new file mode 100644 index 0000000000..5592a20529 --- /dev/null +++ b/addons/@xtermjs/addon-fit/typings/fit.d.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Terminal, ITerminalAddon } from 'xterm'; + +declare module '@xtermjs/addon-fit' { + /** + * An xterm.js addon that enables resizing the terminal to the dimensions of + * its containing element. + */ + export class FitAddon implements ITerminalAddon { + /** + * Creates a new fit addon. + */ + constructor(); + + /** + * Activates the addon + * @param terminal The terminal the addon is being loaded in. + */ + public activate(terminal: Terminal): void; + + /** + * Disposes the addon. + */ + public dispose(): void; + + /** + * Resizes the terminal to the dimensions of its containing element. + */ + public fit(): void; + + /** + * Gets the proposed dimensions that will be used for a fit. + */ + public proposeDimensions(): ITerminalDimensions; + } + + /** + * Reprepresents the dimensions of a terminal. + */ + export interface ITerminalDimensions { + /** + * The number of rows in the terminal. + */ + rows: number; + + /** + * The number of columns in the terminal. + */ + cols: number; + } +} diff --git a/addons/@xtermjs/addon-search/.gitignore b/addons/@xtermjs/addon-search/.gitignore new file mode 100644 index 0000000000..a9f4ed5456 --- /dev/null +++ b/addons/@xtermjs/addon-search/.gitignore @@ -0,0 +1,2 @@ +lib +node_modules \ No newline at end of file diff --git a/addons/@xtermjs/addon-search/.npmignore b/addons/@xtermjs/addon-search/.npmignore new file mode 100644 index 0000000000..e8fc8237a1 --- /dev/null +++ b/addons/@xtermjs/addon-search/.npmignore @@ -0,0 +1,4 @@ +**/*.api.js +**/*.api.ts +tsconfig.json +.yarnrc diff --git a/addons/@xtermjs/addon-search/LICENSE b/addons/@xtermjs/addon-search/LICENSE new file mode 100644 index 0000000000..e597698cc6 --- /dev/null +++ b/addons/@xtermjs/addon-search/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/addons/@xtermjs/addon-search/package.json b/addons/@xtermjs/addon-search/package.json new file mode 100644 index 0000000000..10ab67b518 --- /dev/null +++ b/addons/@xtermjs/addon-search/package.json @@ -0,0 +1,17 @@ +{ + "name": "@xtermjs/addon-search", + "version": "0.1.0-beta4", + "author": { + "name": "The xterm.js authors", + "url": "https://xtermjs.org/" + }, + "main": "lib/SearchAddon.js", + "types": "typings/search.d.ts", + "license": "MIT", + "scripts": { + "prepublishOnly": "../../../node_modules/.bin/tsc -p src" + }, + "peerDependencies": { + "xterm": "^3.14.0" + } +} diff --git a/src/addons/search/SearchHelper.ts b/addons/@xtermjs/addon-search/src/SearchAddon.ts similarity index 90% rename from src/addons/search/SearchHelper.ts rename to addons/@xtermjs/addon-search/src/SearchAddon.ts index e23b14a101..6464db3685 100644 --- a/src/addons/search/SearchHelper.ts +++ b/addons/@xtermjs/addon-search/src/SearchAddon.ts @@ -3,16 +3,57 @@ * @license MIT */ -import { ISearchHelper, ISearchAddonTerminal, ISearchOptions, ISearchResult } from './Interfaces'; -import { IDisposable } from 'xterm'; +import { Terminal, IDisposable, ITerminalAddon } from 'xterm'; + +export interface ISearchOptions { + regex?: boolean; + wholeWord?: boolean; + caseSensitive?: boolean; + incremental?: boolean; +} + +export interface ISearchResult { + term: string; + col: number; + row: number; +} + +// TODO: This is temporary, link to xtem when new version is published +interface INewTerminal extends Terminal { + buffer: IBuffer; + select(column: number, row: number, length: number): void; + getSelectionPosition(): ISelectionPosition | undefined; +} +interface IBuffer { + readonly cursorY: number; + readonly cursorX: number; + readonly viewportY: number; + readonly baseY: number; + readonly length: number; + getLine(y: number): IBufferLine | undefined; +} +interface IBufferLine { + readonly isWrapped: boolean; + getCell(x: number): IBufferCell; + translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string; +} +interface IBufferCell { + readonly char: string; + readonly width: number; +} +interface ISelectionPosition { + startColumn: number; + startRow: number; + endColumn: number; + endRow: number; +} const NON_WORD_CHARACTERS = ' ~!@#$%^&*()+`-=[]{}|\;:"\',./<>?'; const LINES_CACHE_TIME_TO_LIVE = 15 * 1000; // 15 secs -/** - * A class that knows how to search the terminal and how to display the results. - */ -export class SearchHelper implements ISearchHelper { +export class SearchAddon implements ITerminalAddon { + private _terminal: INewTerminal; + /** * translateBufferLineToStringWithWrap is a fairly expensive call. * We memoize the calls into an array that has a time based ttl. @@ -23,10 +64,12 @@ export class SearchHelper implements ISearchHelper { private _cursorMoveListener: IDisposable | undefined; private _resizeListener: IDisposable | undefined; - constructor(private _terminal: ISearchAddonTerminal) { - this._destroyLinesCache = this._destroyLinesCache.bind(this); + public activate(terminal: Terminal): void { + this._terminal = terminal; } + public dispose(): void {} + /** * Find the next instance of the term, then scroll to and select it. If it * doesn't exist, do nothing. diff --git a/addons/@xtermjs/addon-search/src/tsconfig.json b/addons/@xtermjs/addon-search/src/tsconfig.json new file mode 100644 index 0000000000..4d23cc9973 --- /dev/null +++ b/addons/@xtermjs/addon-search/src/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "lib": [ + "dom", + "es6", + ], + "rootDir": ".", + "outDir": "../lib", + "sourceMap": true, + "removeComments": true + }, + "include": [ + "./**/*", + "../../../../typings/xterm.d.ts" + ] +} diff --git a/addons/@xtermjs/addon-search/typings/search.d.ts b/addons/@xtermjs/addon-search/typings/search.d.ts new file mode 100644 index 0000000000..276f0559a2 --- /dev/null +++ b/addons/@xtermjs/addon-search/typings/search.d.ts @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { Terminal, ILinkMatcherOptions, IDisposable, ITerminalAddon } from 'xterm'; + +declare module '@xtermjs/addon-search' { + /** + * Options for a search. + */ + export interface ISearchOptions { + /** + * Whether the search term is a regex. + */ + regex?: boolean; + + /** + * Whether to search for a whole word, the result is only valid if it's + * suppounded in "non-word" characters such as `_`, `(`, `)` or space. + */ + wholeWord?: boolean; + + /** + * Whether the search is case sensitive. + */ + caseSensitive?: boolean; + + /** + * Whether to do an indcremental search, this will expand the selection if it + * still matches the term the user typed. Note that this only affects + * `findNext`, not `findPrevious`. + */ + incremental?: boolean; + } + + /** + * An xterm.js addon that provides search functionality. + */ + export class SearchAddon implements ITerminalAddon { + /** + * Activates the addon + * @param terminal The terminal the addon is being loaded in. + */ + public activate(terminal: Terminal): void; + + /** + * Disposes the addon. + */ + public dispose(): void; + + /** + * Search forwards for the next result that matches the search term and + * options. + * @param term The search term. + * @param searchOptions The options for the search. + */ + public findNext(term: string, searchOptions?: ISearchOptions): boolean; + + /** + * Search backwards for the previous result that matches the search term and + * options. + * @param term The search term. + * @param searchOptions The options for the search. + */ + public findPrevious(term: string, searchOptions?: ISearchOptions): boolean; + } +} diff --git a/addons/@xtermjs/addon-web-links/.gitignore b/addons/@xtermjs/addon-web-links/.gitignore new file mode 100644 index 0000000000..3063f07d55 --- /dev/null +++ b/addons/@xtermjs/addon-web-links/.gitignore @@ -0,0 +1,2 @@ +lib +node_modules diff --git a/addons/@xtermjs/addon-web-links/.npmignore b/addons/@xtermjs/addon-web-links/.npmignore new file mode 100644 index 0000000000..e8fc8237a1 --- /dev/null +++ b/addons/@xtermjs/addon-web-links/.npmignore @@ -0,0 +1,4 @@ +**/*.api.js +**/*.api.ts +tsconfig.json +.yarnrc diff --git a/addons/@xtermjs/addon-web-links/LICENSE b/addons/@xtermjs/addon-web-links/LICENSE new file mode 100644 index 0000000000..e597698cc6 --- /dev/null +++ b/addons/@xtermjs/addon-web-links/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/addons/@xtermjs/addon-web-links/README.md b/addons/@xtermjs/addon-web-links/README.md new file mode 100644 index 0000000000..dc9e1c326b --- /dev/null +++ b/addons/@xtermjs/addon-web-links/README.md @@ -0,0 +1,23 @@ +## xterm-addon-web-links + +[![Build Status](https://dev.azure.com/xtermjs/xterm-addon-web-links/_apis/build/status/xtermjs.xterm-addon-web-links?branchName=master)](https://dev.azure.com/xtermjs/xterm-addon-web-links/_build/latest?definitionId=5&branchName=master) + +An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enabled web links. This addon requires xterm.js 3.14+. + +### Install + +```bash +npm install --save xterm-addon-web-links +``` + +### Usage + +```ts +import { Terminal } from 'xterm'; +import { WebLinksAddon } from 'xterm-addon-web-links'; + +const terminal = new Terminal(); +terminal.loadAddon(new WebLinksAddon()); +``` + +You can also specify a custom handler and options, see the [API](https://github.com/xtermjs/xterm-addon-web-links/blob/master/typings/web-links.d.ts) for more details. diff --git a/addons/@xtermjs/addon-web-links/package.json b/addons/@xtermjs/addon-web-links/package.json new file mode 100644 index 0000000000..546fc12a8d --- /dev/null +++ b/addons/@xtermjs/addon-web-links/package.json @@ -0,0 +1,17 @@ +{ + "name": "@xtermjs/addon-web-links", + "version": "0.1.0-beta7", + "author": { + "name": "The xterm.js authors", + "url": "https://xtermjs.org/" + }, + "main": "lib/WebLinksAddon.js", + "types": "typings/web-links.d.ts", + "license": "MIT", + "scripts": { + "prepublishOnly": "../../../node_modules/.bin/tsc -p src" + }, + "peerDependencies": { + "xterm": "^3.14.0" + } +} diff --git a/addons/@xtermjs/addon-web-links/src/WebLinksAddon.api.ts b/addons/@xtermjs/addon-web-links/src/WebLinksAddon.api.ts new file mode 100644 index 0000000000..2c0044bef1 --- /dev/null +++ b/addons/@xtermjs/addon-web-links/src/WebLinksAddon.api.ts @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import * as puppeteer from 'puppeteer'; +import { assert } from 'chai'; +import { ITerminalOptions } from 'xterm'; + +const APP = 'http://127.0.0.1:3000/test'; + +let browser: puppeteer.Browser; +let page: puppeteer.Page; +const width = 800; +const height = 600; + +describe('WebLinksAddon', () => { + before(async function(): Promise { + this.timeout(10000); + browser = await puppeteer.launch({ + headless: process.argv.indexOf('--headless') !== -1, + slowMo: 80, + args: [`--window-size=${width},${height}`] + }); + page = (await browser.pages())[0]; + await page.setViewport({ width, height }); + }); + + after(async () => { + await browser.close(); + }); + + beforeEach(async function(): Promise { + this.timeout(5000); + await page.goto(APP); + }); + + it('.com', async function(): Promise { + this.timeout(20000); + await testHostName('foo.com'); + }); + + it('.com.au', async function(): Promise { + this.timeout(20000); + await testHostName('foo.com.au'); + }); + + it('.io', async function(): Promise { + this.timeout(20000); + await testHostName('foo.io'); + }); +}); + +async function testHostName(hostname: string): Promise { + await openTerminal({ rendererType: 'dom' }); + await page.evaluate(`window.term.loadAddon(new window.WebLinksAddon())`); + await page.evaluate(` + window.term.writeln(' http://${hostname} '); + window.term.writeln(' http://${hostname}/a~b#c~d?e~f '); + window.term.writeln(' http://${hostname}/colon:test '); + window.term.writeln(' http://${hostname}/colon:test: '); + window.term.writeln('"http://${hostname}/"'); + window.term.writeln('\\'http://${hostname}/\\''); + window.term.writeln('http://${hostname}/subpath/+/id'); + `); + assert.equal(await getLinkAtCell(3, 1), `http://${hostname}`); + assert.equal(await getLinkAtCell(3, 2), `http://${hostname}/a~b#c~d?e~f`); + assert.equal(await getLinkAtCell(3, 3), `http://${hostname}/colon:test`); + assert.equal(await getLinkAtCell(3, 4), `http://${hostname}/colon:test`); + assert.equal(await getLinkAtCell(2, 5), `http://${hostname}/`); + assert.equal(await getLinkAtCell(2, 6), `http://${hostname}/`); + assert.equal(await getLinkAtCell(1, 7), `http://${hostname}/subpath/+/id`); +} + +async function openTerminal(options: ITerminalOptions = {}): Promise { + await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`); + await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`); + if (options.rendererType === 'dom') { + await page.waitForSelector('.xterm-rows'); + } else { + await page.waitForSelector('.xterm-text-layer'); + } +} + +async function getLinkAtCell(col: number, row: number): Promise { + const rowSelector = `.xterm-rows > :nth-child(${row})`; + await page.hover(`${rowSelector} > :nth-child(${col})`); + return await page.evaluate(`Array.prototype.reduce.call(document.querySelectorAll('${rowSelector} > span[style]'), (a, b) => a + b.textContent, '');`); +} diff --git a/src/addons/webLinks/webLinks.ts b/addons/@xtermjs/addon-web-links/src/WebLinksAddon.ts similarity index 62% rename from src/addons/webLinks/webLinks.ts rename to addons/@xtermjs/addon-web-links/src/WebLinksAddon.ts index 8a0fec097f..26d5904b93 100644 --- a/src/addons/webLinks/webLinks.ts +++ b/addons/@xtermjs/addon-web-links/src/WebLinksAddon.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { Terminal, ILinkMatcherOptions } from 'xterm'; +import { Terminal, ILinkMatcherOptions, ITerminalAddon } from 'xterm'; const protocolClause = '(https?:\\/\\/)'; const domainCharacterSet = '[\\da-z\\.-]+'; @@ -29,19 +29,25 @@ function handleLink(event: MouseEvent, uri: string): void { window.open(uri, '_blank'); } -/** - * Initialize the web links addon, registering the link matcher. - * @param term The terminal to use web links within. - * @param handler A custom handler to use. - * @param options Custom options to use, matchIndex will always be ignored. - */ -export function webLinksInit(term: Terminal, handler: (event: MouseEvent, uri: string) => void = handleLink, options: ILinkMatcherOptions = {}): void { - options.matchIndex = 1; - term.registerLinkMatcher(strictUrlRegex, handler, options); -} +export class WebLinksAddon implements ITerminalAddon { + private _linkMatcherId: number | undefined; + private _terminal: Terminal | undefined; + + constructor( + private _handler: (event: MouseEvent, uri: string) => void = handleLink, + private _options: ILinkMatcherOptions = {} + ) { + this._options.matchIndex = 1; + } + + public activate(terminal: Terminal): void { + this._terminal = terminal; + this._linkMatcherId = this._terminal.registerLinkMatcher(strictUrlRegex, this._handler, this._options); + } -export function apply(terminalConstructor: typeof Terminal): void { - (terminalConstructor.prototype).webLinksInit = function (handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void { - webLinksInit(this, handler, options); - }; + public dispose(): void { + if (this._linkMatcherId !== undefined && this._terminal !== undefined) { + this._terminal.deregisterLinkMatcher(this._linkMatcherId); + } + } } diff --git a/src/addons/fit/tsconfig.json b/addons/@xtermjs/addon-web-links/src/tsconfig.json similarity index 51% rename from src/addons/fit/tsconfig.json rename to addons/@xtermjs/addon-web-links/src/tsconfig.json index 3458d23a72..cff0857be8 100644 --- a/src/addons/fit/tsconfig.json +++ b/addons/@xtermjs/addon-web-links/src/tsconfig.json @@ -4,19 +4,16 @@ "target": "es5", "lib": [ "dom", - "es5" + "es2015" ], "rootDir": ".", - "outDir": "../../../lib/addons/fit/", + "outDir": "../lib", "sourceMap": true, "removeComments": true, - "declaration": true, - "types": [ - "../../node_modules/@types/mocha" - ] + "strict": true }, "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" + "./**/*", + "../../../../typings/xterm.d.ts" ] } diff --git a/addons/@xtermjs/addon-web-links/typings/web-links.d.ts b/addons/@xtermjs/addon-web-links/typings/web-links.d.ts new file mode 100644 index 0000000000..fdad54650a --- /dev/null +++ b/addons/@xtermjs/addon-web-links/typings/web-links.d.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + + +import { Terminal, IDisposable, ILinkMatcherOptions } from 'xterm'; + +declare module '@xtermjs/addon-web-links' { + // TODO: This is temporary, link to xterm when the new version is published + export interface ITerminalAddon extends IDisposable { + activate(terminal: Terminal): void; + } + + /** + * An xterm.js addon that enables web links. + */ + export class WebLinksAddon implements ITerminalAddon { + /** + * Creates a new web links addon. + * @param handler The callback when the link is called. + * @param options Options for the link matcher. + */ + constructor(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions); + + /** + * Activates the addon + * @param terminal The terminal the addon is being loaded in. + */ + public activate(terminal: Terminal): void; + + /** + * Disposes the addon. + */ + public dispose(): void; + } +} diff --git a/demo/client.ts b/demo/client.ts index 10d27c864b..6a6de69bc6 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -12,11 +12,10 @@ import { Terminal } from '../out/public/Terminal'; // Use webpacked version (yarn package) // import { Terminal } from '../lib/xterm'; -import { AttachAddon } from 'xterm-addon-attach'; -import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; -import { WebLinksAddon } from 'xterm-addon-web-links'; - -import * as fit from '../lib/addons/fit/fit'; +import { AttachAddon } from '@xtermjs/addon-attach'; +import { FitAddon } from '@xtermjs/addon-fit'; +import { SearchAddon, ISearchOptions } from '@xtermjs/addon-search'; +import { WebLinksAddon } from '@xtermjs/addon-web-links'; // Pulling in the module's types relies on the above, it's looks a // little weird here as we're importing "this" module @@ -25,12 +24,15 @@ import { Terminal as TerminalType, ITerminalOptions } from 'xterm'; export interface IWindowWithTerminal extends Window { term: TerminalType; Terminal?: typeof TerminalType; + AttachAddon?: typeof AttachAddon; + FitAddon?: typeof FitAddon; + SearchAddon?: typeof SearchAddon; + WebLinksAddon?: typeof WebLinksAddon; } declare let window: IWindowWithTerminal; -Terminal.applyAddon(fit); - let term; +let fitAddon: FitAddon; let searchAddon: SearchAddon; let protocol; let socketURL; @@ -74,6 +76,10 @@ const disposeRecreateButtonHandler = () => { if (document.location.pathname === '/test') { window.Terminal = Terminal; + window.AttachAddon = AttachAddon; + window.FitAddon = FitAddon; + window.SearchAddon = SearchAddon; + window.WebLinksAddon = WebLinksAddon; } else { createTerminal(); document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler); @@ -95,6 +101,8 @@ function createTerminal(): void { typedTerm.loadAddon(new WebLinksAddon()); searchAddon = new SearchAddon(); typedTerm.loadAddon(searchAddon); + fitAddon = new FitAddon(); + typedTerm.loadAddon(fitAddon); window.term = term; // Expose `term` to window for debugging purposes term.onResize((size: { cols: number, rows: number }) => { @@ -111,7 +119,7 @@ function createTerminal(): void { socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/'; term.open(terminalContainer); - term.fit(); + fitAddon.fit(); term.focus(); addDomListener(paddingElement, 'change', setPadding); @@ -303,5 +311,5 @@ function updateTerminalSize(): void { const height = (rows * term._core._renderCoordinator.dimensions.actualCellHeight).toString() + 'px'; terminalContainer.style.width = width; terminalContainer.style.height = height; - term.fit(); + fitAddon.fit(); } diff --git a/demo/start.js b/demo/start.js index c9b90c8b6b..20195215d4 100644 --- a/demo/start.js +++ b/demo/start.js @@ -43,7 +43,11 @@ const clientConfig = { ] }, resolve: { - modules: [path.resolve(__dirname, '..'), 'node_modules'], + modules: [ + 'node_modules', + path.resolve(__dirname, '..'), + path.resolve(__dirname, '../addons') + ], extensions: [ '.tsx', '.ts', '.js' ], alias: { common: path.resolve('./out/common'), diff --git a/demo/test.html b/demo/test.html index 275c542def..c14ca4bccc 100644 --- a/demo/test.html +++ b/demo/test.html @@ -2,8 +2,8 @@ xterm.js integration test fixture - - + +
diff --git a/demo/tsconfig.json b/demo/tsconfig.json index 2edfe2f7ca..b30e275df3 100644 --- a/demo/tsconfig.json +++ b/demo/tsconfig.json @@ -1,9 +1,16 @@ { "compilerOptions": { "module": "commonjs", - "target": "es5", + "target": "es2015", "rootDir": ".", - "sourceMap": true + "sourceMap": true, + "baseUrl": ".", + "paths": { + "@xtermjs/addon-attach": ["../addons/@xtermjs/addon-attach"], + "@xtermjs/addon-fit": ["../addons/@xtermjs/addon-fit"], + "@xtermjs/addon-search": ["../addons/@xtermjs/addon-search"], + "@xtermjs/addon-web-links": ["../addons/@xtermjs/addon-web-links"] + } }, "include": [ "client.ts", diff --git a/package.json b/package.json index 0dd8e8f788..56b0bc43ef 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,21 @@ "types": "typings/xterm.d.ts", "repository": "https://github.com/xtermjs/xterm.js", "license": "MIT", + "scripts": { + "prepackage": "npm run build", + "package": "webpack", + "start": "node demo/start", + "lint": "tslint 'src/**/*.ts' './demo/**/*.ts' './addons/**/*.ts'", + "test": "npm run test-unit", + "posttest": "npm run lint", + "test-api": "mocha \"**/*.api.js\"", + "test-unit": "node ./bin/test.js", + "build": "tsc -b ./tsconfig.all.json", + "prepare": "npm run build", + "prepublishOnly": "npm run package", + "watch": "tsc -b -w ./tsconfig.all.json --preserveWatchOutput", + "clean": "rm -rf lib out addons/@xtermjs/*/lib" + }, "devDependencies": { "@types/chai": "^3.4.34", "@types/glob": "^5.0.35", @@ -15,6 +30,7 @@ "@types/puppeteer": "^1.12.4", "@types/utf8": "^2.1.6", "@types/webpack": "^4.4.11", + "@types/ws": "^6.0.1", "chai": "3.5.0", "express": "4.13.4", "express-ws": "2.0.0-rc.1", @@ -31,25 +47,6 @@ "utf8": "^3.0.0", "webpack": "^4.17.1", "webpack-cli": "^3.1.0", - "xterm-addon-attach": "0.1.0-beta8", - "xterm-addon-search": "0.1.0-beta4", - "xterm-addon-web-links": "0.1.0-beta6" - }, - "scripts": { - "prepackage": "npm run build", - "package": "webpack", - "start": "node demo/start", - "start-debug": "node --inspect-brk demo/start", - "start-zmodem": "node demo/zmodem/app", - "lint": "tslint 'src/**/*.ts' './demo/**/*.ts'", - "test-unit": "node ./bin/test.js", - "test": "npm run test-unit", - "posttest": "npm run lint", - "test-api": "mocha \"**/*.api.js\"", - "build": "tsc -b ./src/tsconfig.all.json", - "prepare": "npm run build", - "prepublishOnly": "npm run package", - "coveralls": "nyc report --reporter=text-lcov | coveralls", - "watch": "tsc -b -w ./src/tsconfig.all.json --preserveWatchOutput" + "ws": "^7.0.0" } } diff --git a/src/addons/attach/Interfaces.ts b/src/addons/attach/Interfaces.ts deleted file mode 100644 index 4b2690993d..0000000000 --- a/src/addons/attach/Interfaces.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * 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, IDisposable } from 'xterm'; - -export interface IAttachAddonTerminal extends Terminal { - _core: { - register(d: T): void; - }; - - __socket?: WebSocket; - __attachSocketBuffer?: string; - __dataListener?: IDisposable; - - __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 deleted file mode 100644 index e280b65686..0000000000 --- a/src/addons/attach/attach.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; - -import * as attach from './attach'; - -class MockTerminal {} - -describe('attach addon', () => { - describe('apply', () => { - it('should do register the `attach` and `detach` methods', () => { - 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 deleted file mode 100644 index 2c8a5d4d21..0000000000 --- a/src/addons/attach/attach.ts +++ /dev/null @@ -1,157 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * @license MIT - * - * Implements the attach method, that attaches the terminal to a WebSocket stream. - */ - -import { Terminal, IDisposable } from 'xterm'; -import { IAttachAddonTerminal } from './Interfaces'; - -/** - * Attaches the given terminal to the given socket. - * - * @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: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void { - const addonTerminal = term; - bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional; - addonTerminal.__socket = socket; - - addonTerminal.__flushBuffer = () => { - addonTerminal.write(addonTerminal.__attachSocketBuffer); - addonTerminal.__attachSocketBuffer = null; - }; - - addonTerminal.__pushToBuffer = (data: string) => { - if (addonTerminal.__attachSocketBuffer) { - addonTerminal.__attachSocketBuffer += data; - } else { - addonTerminal.__attachSocketBuffer = data; - setTimeout(addonTerminal.__flushBuffer, 10); - } - }; - - // TODO: This should be typed but there seem to be issues importing the type - let myTextDecoder: any; - - addonTerminal.__getMessage = function(ev: MessageEvent): void { - let str: string; - - if (typeof ev.data === 'object') { - if (!myTextDecoder) { - myTextDecoder = new TextDecoder(); - } - if (ev.data instanceof ArrayBuffer) { - str = myTextDecoder.decode(ev.data); - displayData(str); - } else { - const fileReader = new FileReader(); - - fileReader.addEventListener('load', () => { - str = myTextDecoder.decode(fileReader.result); - displayData(str); - }); - fileReader.readAsArrayBuffer(ev.data); - } - } else if (typeof ev.data === 'string') { - displayData(ev.data); - } else { - throw Error(`Cannot handle "${typeof ev.data}" websocket message.`); - } - }; - - /** - * Push data to buffer or write it in the terminal. - * This is used as a callback for FileReader.onload. - * - * @param str String decoded by FileReader. - * @param data The data of the EventMessage. - */ - function displayData(str?: string, data?: string): void { - if (buffered) { - addonTerminal.__pushToBuffer(str || data); - } else { - addonTerminal.write(str || data); - } - } - - addonTerminal.__sendData = (data: string) => { - if (socket.readyState !== 1) { - return; - } - socket.send(data); - }; - - addonTerminal._core.register(addSocketListener(socket, 'message', addonTerminal.__getMessage)); - - if (bidirectional) { - addonTerminal.__dataListener = addonTerminal.onData(addonTerminal.__sendData); - addonTerminal._core.register(addonTerminal.__dataListener); - } - - addonTerminal._core.register(addSocketListener(socket, 'close', () => detach(addonTerminal, socket))); - addonTerminal._core.register(addSocketListener(socket, 'error', () => detach(addonTerminal, socket))); -} - -function addSocketListener(socket: WebSocket, type: string, handler: (this: WebSocket, ev: Event) => any): IDisposable { - socket.addEventListener(type, handler); - return { - dispose: () => { - if (!handler) { - // Already disposed - return; - } - socket.removeEventListener(type, handler); - handler = null; - } - }; -} - -/** - * Detaches the given terminal from the given socket - * - * @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: Terminal, socket: WebSocket): void { - const addonTerminal = term; - addonTerminal.__dataListener.dispose(); - addonTerminal.__dataListener = undefined; - - socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket; - - if (socket) { - socket.removeEventListener('message', addonTerminal.__getMessage); - } - - delete addonTerminal.__socket; -} - - -export function apply(terminalConstructor: typeof Terminal): void { - /** - * Attaches the current terminal 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. - */ - (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 socket The socket from which to detach the current terminal. - */ - (terminalConstructor.prototype).detach = function (socket: WebSocket): void { - detach(this, socket); - }; -} diff --git a/src/addons/attach/index.html b/src/addons/attach/index.html deleted file mode 100644 index b6f853be8f..0000000000 --- a/src/addons/attach/index.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - -
- -

- xterm.js: socket attach -

-

- Attach the terminal to a WebSocket terminal stream with ease. Perfect for attaching to your - Docker containers. -

-

- Socket information -

-
- - -
-
- -
- - - \ No newline at end of file diff --git a/src/addons/attach/package.json b/src/addons/attach/package.json deleted file mode 100644 index 9e45068b58..0000000000 --- a/src/addons/attach/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.attach", - "main": "attach.js", - "private": true -} diff --git a/src/addons/fit/README.md b/src/addons/fit/README.md deleted file mode 100644 index 68f015894f..0000000000 --- a/src/addons/fit/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## fit addon - -The fit addon adjusts the dimensions of the terminal to match best fit its parent element container. `fit` will only work when the element is visible. diff --git a/src/addons/fit/fit.test.ts b/src/addons/fit/fit.test.ts deleted file mode 100644 index 781b50101e..0000000000 --- a/src/addons/fit/fit.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; - -import * as fit from './fit'; - -class MockTerminal {} - -describe('fit addon', () => { - describe('apply', () => { - it('should do register the `proposeGeometry` and `fit` methods', () => { - 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 deleted file mode 100644 index 26f8752c95..0000000000 --- a/src/addons/fit/fit.ts +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * @license MIT - * - * Fit terminal columns and rows to the dimensions of its DOM element. - * - * ## Approach - * - * Rows: Truncate the division of the terminal parent element height by the - * terminal row height. - * Columns: Truncate the division of the terminal parent element width by the - * terminal character width (apply display: inline at the terminal - * 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: Terminal): IGeometry { - if (!term.element.parentElement) { - return null; - } - const parentElementStyle = window.getComputedStyle(term.element.parentElement); - const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')); - const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width'))); - const elementStyle = window.getComputedStyle(term.element); - const elementPadding = { - top: parseInt(elementStyle.getPropertyValue('padding-top')), - bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')), - right: parseInt(elementStyle.getPropertyValue('padding-right')), - left: parseInt(elementStyle.getPropertyValue('padding-left')) - }; - const elementPaddingVer = elementPadding.top + elementPadding.bottom; - const elementPaddingHor = elementPadding.right + elementPadding.left; - const availableHeight = parentElementHeight - elementPaddingVer; - const availableWidth = parentElementWidth - elementPaddingHor - (term)._core.viewport.scrollBarWidth; - const geometry = { - cols: Math.floor(availableWidth / (term)._core._renderCoordinator.dimensions.actualCellWidth), - rows: Math.floor(availableHeight / (term)._core._renderCoordinator.dimensions.actualCellHeight) - }; - return geometry; -} - -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)._core._renderCoordinator.clear(); - term.resize(geometry.cols, geometry.rows); - } - } -} - -export function apply(terminalConstructor: typeof Terminal): void { - (terminalConstructor.prototype).proposeGeometry = function (): IGeometry { - return proposeGeometry(this); - }; - - (terminalConstructor.prototype).fit = function (): void { - fit(this); - }; -} diff --git a/src/addons/fit/package.json b/src/addons/fit/package.json deleted file mode 100644 index f7cb5bc8c9..0000000000 --- a/src/addons/fit/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.fit", - "main": "fit.js", - "private": true -} diff --git a/src/addons/fullscreen/fullscreen.css b/src/addons/fullscreen/fullscreen.css deleted file mode 100644 index 60e8c5114c..0000000000 --- a/src/addons/fullscreen/fullscreen.css +++ /dev/null @@ -1,10 +0,0 @@ -.xterm.fullscreen { - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - width: auto; - height: auto; - z-index: 255; -} diff --git a/src/addons/fullscreen/fullscreen.test.ts b/src/addons/fullscreen/fullscreen.test.ts deleted file mode 100644 index 6d41bdfda6..0000000000 --- a/src/addons/fullscreen/fullscreen.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; - -import * as fullscreen from './fullscreen'; - -class MockTerminal {} - -describe('fullscreen addon', () => { - describe('apply', () => { - it('should do register the `toggleFullscreen` method', () => { - fullscreen.apply(MockTerminal); - assert.equal(typeof (MockTerminal).prototype.toggleFullScreen, 'function'); - }); - }); -}); diff --git a/src/addons/fullscreen/fullscreen.ts b/src/addons/fullscreen/fullscreen.ts deleted file mode 100644 index 083c00c24b..0000000000 --- a/src/addons/fullscreen/fullscreen.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2014 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Terminal } from 'xterm'; - -/** - * Toggle the given terminal's fullscreen mode. - * @param term The terminal to toggle full screen mode - * @param fullscreen Toggle fullscreen on (true) or off (false) - */ -export function toggleFullScreen(term: Terminal, fullscreen: boolean): void { - let fn: (...tokens: string[]) => void; - - if (typeof fullscreen === 'undefined') { - fn = (term.element.classList.contains('fullscreen')) ? - term.element.classList.remove : term.element.classList.add; - } else if (!fullscreen) { - fn = term.element.classList.remove; - } else { - fn = term.element.classList.add; - } - - fn = fn.bind(term.element.classList); - fn('fullscreen'); -} - -export function apply(terminalConstructor: typeof Terminal): void { - (terminalConstructor.prototype).toggleFullScreen = function (fullscreen: boolean): void { - toggleFullScreen(this, fullscreen); - }; -} diff --git a/src/addons/fullscreen/package.json b/src/addons/fullscreen/package.json deleted file mode 100644 index fdaf6880ba..0000000000 --- a/src/addons/fullscreen/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.fullscreen", - "main": "fullscreen.js", - "private": true -} diff --git a/src/addons/fullscreen/tsconfig.json b/src/addons/fullscreen/tsconfig.json deleted file mode 100644 index 0c74c25c02..0000000000 --- a/src/addons/fullscreen/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ - "dom", - "es5" - ], - "rootDir": ".", - "outDir": "../../../lib/addons/fullscreen/", - "sourceMap": true, - "removeComments": true, - "declaration": true, - "types": [ - "../../node_modules/@types/mocha" - ] - }, - "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" - ] -} diff --git a/src/addons/search/Interfaces.ts b/src/addons/search/Interfaces.ts deleted file mode 100644 index 872537ea3c..0000000000 --- a/src/addons/search/Interfaces.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Terminal } from 'xterm'; - -export interface ISearchAddonTerminal extends Terminal { - __searchHelper?: ISearchHelper; -} - -export interface ISearchHelper { - findNext(term: string, searchOptions: ISearchOptions): boolean; - findPrevious(term: string, searchOptions: ISearchOptions): boolean; -} - -export interface ISearchOptions { - regex?: boolean; - wholeWord?: boolean; - caseSensitive?: boolean; - /** - * Use this when you want the selection to expand if it still matches as the - * user types. Note that this only affects findNext. - */ - incremental?: boolean; -} - -export interface ISearchResult { - term: string; - col: number; - row: number; -} diff --git a/src/addons/search/package.json b/src/addons/search/package.json deleted file mode 100644 index 552e9332b5..0000000000 --- a/src/addons/search/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.search", - "main": "search.js", - "private": true -} diff --git a/src/addons/search/search.test.ts b/src/addons/search/search.test.ts deleted file mode 100644 index 262b475f16..0000000000 --- a/src/addons/search/search.test.ts +++ /dev/null @@ -1,358 +0,0 @@ -/** - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - * @license MIT - */ -declare var require: any; - -import { assert, expect } from 'chai'; -import * as search from './search'; -import { SearchHelper } from './SearchHelper'; -import { ISearchOptions, ISearchResult } from './Interfaces'; - -class MockTerminalPlain {} - -class MockTerminal { - private _core: any; - public searchHelper: TestSearchHelper; - public cols: number; - constructor(options: any) { - this._core = new (require('../../../out/Terminal')).Terminal(options); - this.searchHelper = new TestSearchHelper(this as any); - this.cols = options.cols; - } - get core(): any { - return this._core; - } - get buffer(): IBuffer { - // TODO: This is a hacky workaround until we use puppeteer for addon tests - const buffer = this._core.buffer; - return { - cursorY: buffer.y, - cursorX: buffer.x, - viewportY: buffer.ydisp, - baseY: buffer.ybase, - length: buffer.length, - getLine(y: number): IBufferLine { - return { - isWrapped: buffer.lines.get(y) ? buffer.lines.get(y).isWrapped : false, - getCell(x: number): IBufferCell { - return { - char: buffer.lines.get(y).get(x)[1/*CHAR_DATA_CHAR_INDEX*/], - width: buffer.lines.get(y).get(x)[2/*CHAR_DATA_WIDTH_INDEX*/] - }; - }, - translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string { - return buffer.translateBufferLineToString(y, trimRight); - } - }; - } - }; - } - pushWriteData(): void { - this._core._innerWrite(); - } -} - -interface IBuffer { - readonly cursorY: number; - readonly cursorX: number; - readonly viewportY: number; - readonly baseY: number; - readonly length: number; - getLine(y: number): IBufferLine | undefined; -} - -interface IBufferLine { - readonly isWrapped: boolean; - getCell(x: number): IBufferCell; - translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string; -} - -interface IBufferCell { - readonly char: string; - readonly width: number; -} - -class TestSearchHelper extends SearchHelper { - public findInLine(term: string, rowNumber: number, searchOptions?: ISearchOptions): ISearchResult { - return this._findInLine(term, rowNumber, 0, searchOptions); - } - public findFromIndex(term: string, row: number, col: number, searchOptions?: ISearchOptions, isReverseSearch?: boolean): ISearchResult { - return this._findInLine(term, row, col, searchOptions, isReverseSearch); - } -} - -describe('search addon', () => { - describe('apply', () => { - it('should register findNext and findPrevious', () => { - search.apply(MockTerminalPlain); - assert.equal(typeof (MockTerminalPlain).prototype.findNext, 'function'); - assert.equal(typeof (MockTerminalPlain).prototype.findPrevious, 'function'); - }); - }); - describe('find', () => { - it('Searchhelper - should find correct position', () => { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 3}); - term.core.write('Hello World\r\ntest\n123....hello'); - term.pushWriteData(); - const hello0 = term.searchHelper.findInLine('Hello', 0); - const hello1 = term.searchHelper.findInLine('Hello', 1); - const hello2 = term.searchHelper.findInLine('Hello', 2); - expect(hello0).eql({col: 0, row: 0, term: 'Hello'}); - expect(hello1).eql(undefined); - expect(hello2).eql({col: 11, row: 2, term: 'Hello'}); - }); - it('should find search term accross line wrap', () => { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 10, rows: 5}); - term.core.write('texttextHellotext\r\n'); - term.core.write('texttexttextHellotext goodbye'); - term.pushWriteData(); - /* - texttextHe - llotext - texttextte - xtHellotex - t (these spaces included intentionally) - goodbye - */ - - const hello0 = term.searchHelper.findInLine('Hello', 0); - const hello1 = term.searchHelper.findInLine('Hello', 1); - const hello2 = term.searchHelper.findInLine('Hello', 2); - const hello3 = term.searchHelper.findInLine('Hello', 3); - const llo = term.searchHelper.findInLine('llo', 1); - const goodbye = term.searchHelper.findInLine('goodbye', 2); - expect(hello0).eql({col: 8, row: 0, term: 'Hello'}); - expect(hello1).eql(undefined); - expect(hello2).eql({col: 2, row: 3, term: 'Hello'}); - expect(hello3).eql(undefined); - expect(llo).eql(undefined); - expect(goodbye).eql({col: 0, row: 5, term: 'goodbye'}); - term.core.resize(9, 5); - const hello0Resize = term.searchHelper.findInLine('Hello', 0); - expect(hello0Resize).eql({col: 8, row: 0, term: 'Hello'}); - }); - it('should respect search regex', () => { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 10, rows: 4}); - term.core.write('abcdefghijklmnopqrstuvwxyz\r\n~/dev '); - /* - abcdefghij - klmnopqrst - uvwxyz - ~/dev - */ - term.pushWriteData(); - const searchOptions = { - regex: true, - wholeWord: false, - caseSensitive: false - }; - const hello0 = term.searchHelper.findInLine('dee*', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('jkk*', 0, searchOptions); - const hello2 = term.searchHelper.findInLine('mnn*', 1, searchOptions); - const tilda0 = term.searchHelper.findInLine('^~', 3, searchOptions); - const tilda1 = term.searchHelper.findInLine('^[~]', 3, searchOptions); - const tilda2 = term.searchHelper.findInLine('^\\~', 3, searchOptions); - expect(hello0).eql({col: 3, row: 0, term: 'de'}); - expect(hello1).eql({col: 9, row: 0, term: 'jk'}); - expect(hello2).eql(undefined); - expect(tilda0).eql({col: 0, row: 3, term: '~'}); - expect(tilda1).eql({col: 0, row: 3, term: '~'}); - expect(tilda2).eql({col: 0, row: 3, term: '~'}); - }); - it('should not select empty lines', () => { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 3}); - const line = term.searchHelper.findInLine('^.*$', 0, { regex: true }); - expect(line).eql(undefined); - }); - it('should respect case sensitive', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 4}); - term.core.write('Hello World\r\n123....hello\r\nmoreTestHello'); - term.pushWriteData(); - const searchOptions = { - regex: false, - wholeWord: false, - caseSensitive: true - }; - const hello0 = term.searchHelper.findInLine('Hello', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('Hello', 1, searchOptions); - const hello2 = term.searchHelper.findInLine('Hello', 2, searchOptions); - expect(hello0).eql({col: 0, row: 0, term: 'Hello'}); - expect(hello1).eql(undefined); - expect(hello2).eql({col: 8, row: 2, term: 'Hello'}); - }); - it('should respect case sensitive + regex', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 4}); - term.core.write('hellohello\r\nHelloHello'); - term.pushWriteData(); - - /** - * hellohello - * HelloHello - */ - - const searchOptions = { - regex: true, - wholeWord: false, - caseSensitive: true - }; - const hello0 = term.searchHelper.findInLine('Hello', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('Hello$', 0, searchOptions); - const hello2 = term.searchHelper.findInLine('Hello', 1, searchOptions); - const hello3 = term.searchHelper.findInLine('Hello$', 1, searchOptions); - expect(hello0).eql(undefined); - expect(hello1).eql(undefined); - expect(hello2).eql({col: 0, row: 1, term: 'Hello'}); - expect(hello3).eql({col: 5, row: 1, term: 'Hello'}); - }); - it('should respect whole-word search option', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('Hello World\r\nWorld Hello\r\nWorldHelloWorld\r\nHelloWorld\r\nWorldHello'); - term.pushWriteData(); - const searchOptions = { - regex: false, - wholeWord: true, - caseSensitive: false - }; - const hello0 = term.searchHelper.findInLine('Hello', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('Hello', 1, searchOptions); - const hello2 = term.searchHelper.findInLine('Hello', 2, searchOptions); - const hello3 = term.searchHelper.findInLine('Hello', 3, searchOptions); - const hello4 = term.searchHelper.findInLine('Hello', 4, searchOptions); - expect(hello0).eql({col: 0, row: 0, term: 'Hello'}); - expect(hello1).eql({col: 6, row: 1, term: 'Hello'}); - expect(hello2).eql(undefined); - expect(hello3).eql(undefined); - expect(hello4).eql(undefined); - }); - it('should respect whole-word + case sensitive search options', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('Hello World\r\nHelloWorld'); - term.pushWriteData(); - const searchOptions = { - regex: false, - wholeWord: true, - caseSensitive: true - }; - const hello0 = term.searchHelper.findInLine('Hello', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('hello', 0, searchOptions); - const hello2 = term.searchHelper.findInLine('Hello', 1, searchOptions); - const hello3 = term.searchHelper.findInLine('hello', 1, searchOptions); - expect(hello0).eql({col: 0, row: 0, term: 'Hello'}); - expect(hello1).eql(undefined); - expect(hello2).eql(undefined); - expect(hello3).eql(undefined); - }); - it('should respect whole-word + regex search options', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('Hello World Hello\r\nHelloWorldHello'); - term.pushWriteData(); - const searchOptions = { - regex: true, - wholeWord: true, - caseSensitive: false - }; - const hello0 = term.searchHelper.findInLine('Hello', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('Hello$', 0, searchOptions); - const hello2 = term.searchHelper.findInLine('Hello', 1, searchOptions); - const hello3 = term.searchHelper.findInLine('Hello$', 1, searchOptions); - expect(hello0).eql({col: 0, row: 0, term: 'hello'}); - expect(hello1).eql({col: 12, row: 0, term: 'hello'}); - expect(hello2).eql(undefined); - expect(hello3).eql(undefined); - }); - it('should respect all search options', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('Hello World Hello\r\nHelloWorldHello'); - term.pushWriteData(); - const searchOptions = { - regex: true, - wholeWord: true, - caseSensitive: true - }; - const hello0 = term.searchHelper.findInLine('Hello', 0, searchOptions); - const hello1 = term.searchHelper.findInLine('Hello$', 0, searchOptions); - const hello2 = term.searchHelper.findInLine('hello', 0, searchOptions); - const hello3 = term.searchHelper.findInLine('hello$', 0, searchOptions); - const hello4 = term.searchHelper.findInLine('hello', 1, searchOptions); - const hello5 = term.searchHelper.findInLine('hello$', 1, searchOptions); - expect(hello0).eql({col: 0, row: 0, term: 'Hello'}); - expect(hello1).eql({col: 12, row: 0, term: 'Hello'}); - expect(hello2).eql(undefined); - expect(hello3).eql(undefined); - expect(hello4).eql(undefined); - expect(hello5).eql(undefined); - }); - it('should find multiple matches in line', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('helloooo helloooo\r\naaaAAaaAAA'); - term.pushWriteData(); - const searchOptions = { - regex: false, - wholeWord: false, - caseSensitive: false - }; - const find0 = term.searchHelper.findFromIndex('hello', 0, 0, searchOptions); - const find1 = term.searchHelper.findFromIndex('hello', 0, find0.col + find0.term.length, searchOptions); - const find2 = term.searchHelper.findFromIndex('aaaa', 1, 0, searchOptions); - const find3 = term.searchHelper.findFromIndex('aaaa', 1, find2.col + find2.term.length, searchOptions); - const find4 = term.searchHelper.findFromIndex('aaaa', 1, find3.col + find3.term.length, searchOptions); - expect(find0).eql({col: 0, row: 0, term: 'hello'}); - expect(find1).eql({col: 9, row: 0, term: 'hello'}); - expect(find2).eql({col: 0, row: 1, term: 'aaaa'}); - expect(find3).eql({col: 4, row: 1, term: 'aaaa'}); - expect(find4).eql(undefined); - }); - it('should find multiple matches in line - reverse search', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('it is what it is'); - term.pushWriteData(); - const searchOptions = { - regex: false, - wholeWord: false, - caseSensitive: false - }; - const isReverseSearch = true; - const find0 = term.searchHelper.findFromIndex('is', 0, 16, searchOptions, isReverseSearch); - const find1 = term.searchHelper.findFromIndex('is', 0, find0.col, searchOptions, isReverseSearch); - const find2 = term.searchHelper.findFromIndex('it', 0, 16, searchOptions, isReverseSearch); - const find3 = term.searchHelper.findFromIndex('it', 0, find2.col, searchOptions, isReverseSearch); - expect(find0).eql({col: 14, row: 0, term: 'is'}); - expect(find1).eql({col: 3, row: 0, term: 'is'}); - expect(find2).eql({col: 11, row: 0, term: 'it'}); - expect(find3).eql({col: 0, row: 0, term: 'it'}); - }); - it('should find multiple matches in line - reverse search with regex', function(): void { - search.apply(MockTerminal); - const term = new MockTerminal({cols: 20, rows: 5}); - term.core.write('zzzABCzzzzABCABC'); - term.pushWriteData(); - const searchOptions = { - regex: true, - wholeWord: false, - caseSensitive: true - }; - const isReverseSearch = true; - const find0 = term.searchHelper.findFromIndex('[A-Z]{3}', 0, 16, searchOptions, isReverseSearch); - const find1 = term.searchHelper.findFromIndex('[A-Z]{3}', 0, find0.col, searchOptions, isReverseSearch); - const find2 = term.searchHelper.findFromIndex('[A-Z]{3}', 0, find1.col, searchOptions, isReverseSearch); - const find3 = term.searchHelper.findFromIndex('[A-Z]{3}', 0, find2.col, searchOptions, isReverseSearch); - expect(find0).eql({col: 13, row: 0, term: 'ABC'}); - expect(find1).eql({col: 10, row: 0, term: 'ABC'}); - expect(find2).eql({col: 3, row: 0, term: 'ABC'}); - expect(find3).eql(undefined); - }); - }); -}); diff --git a/src/addons/search/search.ts b/src/addons/search/search.ts deleted file mode 100644 index c274f28a67..0000000000 --- a/src/addons/search/search.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { SearchHelper } from './SearchHelper'; -import { Terminal } from 'xterm'; -import { ISearchAddonTerminal, ISearchOptions } from './Interfaces'; - -/** - * Find the next instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The search term. - * @param searchOptions Search options - * @return Whether a result was found. - */ -export function findNext(terminal: Terminal, term: string, searchOptions: ISearchOptions = {}): boolean { - const addonTerminal = terminal; - if (!addonTerminal.__searchHelper) { - addonTerminal.__searchHelper = new SearchHelper(addonTerminal); - } - return addonTerminal.__searchHelper.findNext(term, searchOptions); -} - -/** - * Find the previous instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The search term. - * @param searchOptions Search options - * @return Whether a result was found. - */ -export function findPrevious(terminal: Terminal, term: string, searchOptions: ISearchOptions): boolean { - const addonTerminal = terminal; - if (!addonTerminal.__searchHelper) { - addonTerminal.__searchHelper = new SearchHelper(addonTerminal); - } - return addonTerminal.__searchHelper.findPrevious(term, searchOptions); -} - -export function apply(terminalConstructor: typeof Terminal): void { - (terminalConstructor.prototype).findNext = function(term: string, searchOptions: ISearchOptions): boolean { - return findNext(this, term, searchOptions); - }; - - (terminalConstructor.prototype).findPrevious = function(term: string, searchOptions: ISearchOptions): boolean { - return findPrevious(this, term, searchOptions); - }; -} diff --git a/src/addons/search/tsconfig.json b/src/addons/search/tsconfig.json deleted file mode 100644 index 6a1611a51d..0000000000 --- a/src/addons/search/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ - "dom", - "es5" - ], - "rootDir": ".", - "outDir": "../../../lib/addons/search/", - "sourceMap": true, - "removeComments": true, - "declaration": true, - "types": [ - "../../node_modules/@types/mocha" - ] - }, - "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" - ] -} diff --git a/src/addons/terminado/Interfaces.ts b/src/addons/terminado/Interfaces.ts deleted file mode 100644 index dd7b045ca6..0000000000 --- a/src/addons/terminado/Interfaces.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 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, IDisposable } from 'xterm'; - -export interface ITerminadoAddonTerminal extends Terminal { - _core: { - register(d: T): void; - }; - - __socket?: WebSocket; - __attachSocketBuffer?: string; - __dataListener?: IDisposable; - - __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/package.json b/src/addons/terminado/package.json deleted file mode 100644 index d695959224..0000000000 --- a/src/addons/terminado/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.terminado", - "main": "terminado.js", - "private": true -} diff --git a/src/addons/terminado/terminado.test.ts b/src/addons/terminado/terminado.test.ts deleted file mode 100644 index e46eafdfa7..0000000000 --- a/src/addons/terminado/terminado.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; - -import * as terminado from './terminado'; - -class MockTerminal {} - -describe('terminado addon', () => { - describe('apply', () => { - it('should do register the `terminadoAttach` and `terminadoDetach` methods', () => { - 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 deleted file mode 100644 index 9895a07b83..0000000000 --- a/src/addons/terminado/terminado.ts +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - * - * This module provides methods for attaching a terminal to a terminado - * WebSocket stream. - */ - -import { Terminal } from 'xterm'; -import { ITerminadoAddonTerminal } from './Interfaces'; - -/** - * Attaches the given terminal to the given socket. - * - * @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: Terminal, socket: WebSocket, bidirectional: boolean, buffered: boolean): void { - const addonTerminal = term; - bidirectional = (typeof bidirectional === 'undefined') ? true : bidirectional; - addonTerminal.__socket = socket; - - addonTerminal.__flushBuffer = () => { - addonTerminal.write(addonTerminal.__attachSocketBuffer); - addonTerminal.__attachSocketBuffer = null; - }; - - addonTerminal.__pushToBuffer = (data: string) => { - if (addonTerminal.__attachSocketBuffer) { - addonTerminal.__attachSocketBuffer += data; - } else { - addonTerminal.__attachSocketBuffer = data; - setTimeout(addonTerminal.__flushBuffer, 10); - } - }; - - addonTerminal.__getMessage = (ev: MessageEvent) => { - const data = JSON.parse(ev.data); - if (data[0] === 'stdout') { - if (buffered) { - addonTerminal.__pushToBuffer(data[1]); - } else { - addonTerminal.write(data[1]); - } - } - }; - - addonTerminal.__sendData = (data: string) => { - socket.send(JSON.stringify(['stdin', data])); - }; - - addonTerminal.__setSize = (size: {rows: number, cols: number}) => { - socket.send(JSON.stringify(['set_size', size.rows, size.cols])); - }; - - socket.addEventListener('message', addonTerminal.__getMessage); - - if (bidirectional) { - addonTerminal._core.register(addonTerminal.onData(addonTerminal.__sendData)); - } - addonTerminal._core.register(addonTerminal.onResize(addonTerminal.__setSize)); - - socket.addEventListener('close', () => terminadoDetach(addonTerminal, socket)); - socket.addEventListener('error', () => terminadoDetach(addonTerminal, socket)); -} - -/** - * Detaches the given terminal from the given socket - * - * @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: Terminal, socket: WebSocket): void { - const addonTerminal = term; - addonTerminal.__dataListener.dispose(); - addonTerminal.__dataListener = undefined; - - socket = (typeof socket === 'undefined') ? addonTerminal.__socket : socket; - - if (socket) { - socket.removeEventListener('message', addonTerminal.__getMessage); - } - - delete addonTerminal.__socket; -} - -export function apply(terminalConstructor: typeof Terminal): void { - /** - * Attaches the current terminal 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. - */ - (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 socket The socket from which to detach the current terminal. - */ - (terminalConstructor.prototype).terminadoDetach = function (socket: WebSocket): void { - return terminadoDetach(this, socket); - }; -} diff --git a/src/addons/terminado/tsconfig.json b/src/addons/terminado/tsconfig.json deleted file mode 100644 index e2e194457e..0000000000 --- a/src/addons/terminado/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ - "es5" - ], - "rootDir": ".", - "outDir": "../../../lib/addons/terminado/", - "sourceMap": true, - "removeComments": true, - "declaration": true, - "types": [ - "../../node_modules/@types/mocha" - ] - }, - "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" - ] -} diff --git a/src/addons/webLinks/package.json b/src/addons/webLinks/package.json deleted file mode 100644 index f200cab4a1..0000000000 --- a/src/addons/webLinks/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.weblinks", - "main": "weblinks.js", - "private": true -} diff --git a/src/addons/webLinks/tsconfig.json b/src/addons/webLinks/tsconfig.json deleted file mode 100644 index 9c4f117606..0000000000 --- a/src/addons/webLinks/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ - "dom", - "es5", - ], - "rootDir": ".", - "outDir": "../../../lib/addons/webLinks/", - "sourceMap": true, - "removeComments": true, - "declaration": true, - "types": [ - "../../node_modules/@types/mocha" - ] - }, - "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" - ] -} diff --git a/src/addons/webLinks/webLinks.test.ts b/src/addons/webLinks/webLinks.test.ts deleted file mode 100644 index da5569ab81..0000000000 --- a/src/addons/webLinks/webLinks.test.ts +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; - -import * as webLinks from './webLinks'; - -class MockTerminal { - public regex: RegExp; - public handler: (event: MouseEvent, uri: string) => void; - public options?: any; - - public registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: any): number { - this.regex = regex; - this.handler = handler; - this.options = options; - return 0; - } -} - -describe('webLinks addon', () => { - describe('apply', () => { - it('should do register the `webLinksInit` method', () => { - webLinks.apply(MockTerminal); - assert.equal(typeof (MockTerminal).prototype.webLinksInit, 'function'); - }); - }); - - describe('should allow simple URI path', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://foo.com '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://bar.io '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io'); - }); - }); - - describe('should allow ~ character in URI path', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://foo.com/a~b#c~d?e~f '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com/a~b#c~d?e~f'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://bar.io/a~b#c~d?e~f '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io/a~b#c~d?e~f'); - }); - }); - - describe('should allow : character in URI path', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://foo.com/colon:test '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com/colon:test'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://bar.io/colon:test '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io/colon:test'); - }); - }); - - describe('should not allow : character at the end of a URI path', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://foo.com/colon:test: '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com/colon:test'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = ' http://bar.io/colon:test: '; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io/colon:test'); - }); - }); - - describe('should not allow " character at the end of a URI enclosed with ""', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = '"http://foo.com/"'; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com/'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = '"http://bar.io/"'; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io/'); - }); - }); - - describe('should not allow \' character at the end of a URI enclosed with \'\'', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = '\'http://foo.com/\''; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com/'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = '\'http://bar.io/\''; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io/'); - }); - }); - - describe('should allow + character in URI path', () => { - it('foo.com', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = 'http://foo.com/subpath/+/id'; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://foo.com/subpath/+/id'); - }); - - it('bar.io', () => { - const term = new MockTerminal(); - webLinks.webLinksInit(term); - - const row = 'http://bar.io/subpath/+/id'; - - const match = row.match(term.regex); - const uri = match[term.options.matchIndex]; - - assert.equal(uri, 'http://bar.io/subpath/+/id'); - }); - }); -}); diff --git a/src/addons/zmodem/package.json b/src/addons/zmodem/package.json deleted file mode 100644 index 218130ab5a..0000000000 --- a/src/addons/zmodem/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "xterm.zmodem", - "main": "zmodem.js", - "private": true -} diff --git a/src/addons/zmodem/tsconfig.json b/src/addons/zmodem/tsconfig.json deleted file mode 100644 index 7d821b7c51..0000000000 --- a/src/addons/zmodem/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ - "es5" - ], - "rootDir": ".", - "outDir": "../../../lib/addons/zmodem/", - "sourceMap": true, - "removeComments": true, - "declaration": true, - "types": [ - "../../node_modules/@types/mocha" - ] - }, - "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" - ] -} diff --git a/src/addons/zmodem/zmodem.test.ts b/src/addons/zmodem/zmodem.test.ts deleted file mode 100644 index d0c7c5fb42..0000000000 --- a/src/addons/zmodem/zmodem.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; - -import * as zmodem from './zmodem'; - -class MockTerminal {} - -describe('zmodem addon', () => { - describe('apply', () => { - it('should do register the `zmodemAttach` method and `zmodemBrowser` attribute', () => { - 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 deleted file mode 100644 index 70fc6e98b2..0000000000 --- a/src/addons/zmodem/zmodem.ts +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 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. - * - * This addon is a wrapper around zmodem.js. It adds the following to the - * Terminal class: - * - * - function `zmodemAttach(, )` - creates a Zmodem.Sentry - * on the passed WebSocket object. The Object passed is optional and - * can contain: - * - noTerminalWriteOutsideSession: Suppress writes from the Sentry - * object to the Terminal while there is no active Session. This - * is necessary for compatibility with, for example, the - * `attach.js` addon. - * - * - event `zmodemDetect` - fired on Zmodem.Sentry’s `on_detect` callback. - * Passes the zmodem.js Detection object. - * - * - event `zmodemRetract` - fired on Zmodem.Sentry’s `on_retract` callback. - * - * You’ll need to provide logic to handle uploads and downloads. - * See zmodem.js’s documentation for more details. - * - * **IMPORTANT:** After you confirm() a zmodem.js Detection, if you have - * used the `attach` or `terminado` addons, you’ll need to suspend their - * operation for the duration of the ZMODEM session. (The demo does this - * via `detach()` and a re-`attach()`.) - */ - -let zmodem: any; - -export interface IZmodemOptions { - noTerminalWriteOutsideSession?: boolean; -} - -function zmodemAttach(ws: WebSocket, opts: IZmodemOptions = {}): void { - const term = this; - const senderFunc = (octets: ArrayLike) => ws.send(new Uint8Array(octets)); - - let zsentry: any; - - function shouldWrite(): boolean { - return !!zsentry.get_confirmed_session() || !opts.noTerminalWriteOutsideSession; - } - - zsentry = new zmodem.Sentry({ - to_terminal: (octets: ArrayLike) => { - if (shouldWrite()) { - term.write( - String.fromCharCode.apply(String, octets) - ); - } - }, - sender: senderFunc, - on_retract: () => (term).emit('zmodemRetract'), - on_detect: (detection: any) => (term).emit('zmodemDetect', detection) - }); - - function handleWSMessage(evt: MessageEvent): void { - - // In testing with xterm.js’s demo the first message was - // always text even if the rest were binary. While that - // may be specific to xterm.js’s demo, ultimately we - // should reject anything that isn’t binary. - if (typeof evt.data === 'string') { - if (shouldWrite()) { - term.write(evt.data); - } - } - else { - zsentry.consume(evt.data); - } - } - - ws.binaryType = 'arraybuffer'; - ws.addEventListener('message', handleWSMessage); -} - -export function apply(terminalConstructor: typeof Terminal): void { - zmodem = (typeof window === 'object') ? (window).Zmodem : {Browser: null}; // Nullify browser for tests - - (terminalConstructor.prototype).zmodemAttach = zmodemAttach; - (terminalConstructor.prototype).zmodemBrowser = zmodem.Browser; -} diff --git a/src/public/Terminal.test.ts b/src/public/Terminal.test.ts deleted file mode 100644 index 6bad5b0440..0000000000 --- a/src/public/Terminal.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2016 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { assert } from 'chai'; -import { Terminal } from './Terminal'; -import * as attach from '../addons/attach/attach'; - - describe('Terminal', () => { - it('should apply addons with Terminal.applyAddon', () => { - Terminal.applyAddon(attach); - // Test that addon was applied successfully, adding attach to Terminal's - // prototype. - assert.equal(typeof (Terminal).prototype.attach, 'function'); - }); -}); diff --git a/src/tsconfig.all.json b/src/tsconfig.all.json deleted file mode 100644 index 2a53ab8994..0000000000 --- a/src/tsconfig.all.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "files": [], - "include": [], - "references": [ - { "path": "." }, - { "path": "./addons/attach" }, - { "path": "./addons/fit" }, - { "path": "./addons/fullscreen" }, - { "path": "./addons/search" }, - { "path": "./addons/terminado" }, - { "path": "./addons/webLinks" }, - { "path": "./addons/zmodem" } - ] -} diff --git a/tsconfig.all.json b/tsconfig.all.json new file mode 100644 index 0000000000..8d38d0125a --- /dev/null +++ b/tsconfig.all.json @@ -0,0 +1,11 @@ +{ + "files": [], + "include": [], + "references": [ + { "path": "./src" }, + { "path": "./addons/@xtermjs/addon-attach/src" }, + { "path": "./addons/@xtermjs/addon-fit/src" }, + { "path": "./addons/@xtermjs/addon-search/src" }, + { "path": "./addons/@xtermjs/addon-web-links/src" } + ] +} diff --git a/yarn.lock b/yarn.lock index a453bb236e..61a7062987 100644 --- a/yarn.lock +++ b/yarn.lock @@ -108,6 +108,14 @@ "@types/uglify-js" "*" source-map "^0.6.0" +"@types/ws@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.1.tgz#ca7a3f3756aa12f62a0a62145ed14c6db25d5a28" + integrity sha512-EzH8k1gyZ4xih/MaZTXwT2xOkPiIMSrhQ9b8wrlX88L0T02eYsddatQlwVFlEPyEqV0ChpdpNnE51QPH6NVT4Q== + dependencies: + "@types/events" "*" + "@types/node" "*" + "@webassemblyjs/ast@1.5.13": version "1.5.13" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25" @@ -472,7 +480,7 @@ async-each@^1.0.0: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" integrity sha1-GdOGodntxufByF04iu28xW0zYC0= -async-limiter@~1.0.0: +async-limiter@^1.0.0, async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== @@ -4536,6 +4544,13 @@ ws@^6.1.0: dependencies: async-limiter "~1.0.0" +ws@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.0.0.tgz#79351cbc3f784b3c20d0821baf4b4ff809ffbf51" + integrity sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg== + dependencies: + async-limiter "^1.0.0" + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" @@ -4551,21 +4566,6 @@ xtend@^4.0.0, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= -xterm-addon-attach@0.1.0-beta8: - version "0.1.0-beta8" - resolved "https://registry.yarnpkg.com/xterm-addon-attach/-/xterm-addon-attach-0.1.0-beta8.tgz#e469ed9d6ab7e535d0a9ffae23ef4f2efe58163b" - integrity sha512-HtQuwqnvcR+SwI9/JbBMd//Il+oEeo3rWrIucLLKHT8sB+OAOkdhmo5KIM/hhnovjI040WJ+tTHkDgPFwIJtmw== - -xterm-addon-search@0.1.0-beta4: - version "0.1.0-beta4" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.1.0-beta4.tgz#c73fe058c87f07eaae31baaa92976e927438a396" - integrity sha512-tJgZ1VTRd/DOFUhSFZzybRF8SR1LCEXRYkw/mHzGV5Ba3zhqVdSkN/0J9sjOpX6u21buee2OmTiCMZxq80zfJg== - -xterm-addon-web-links@0.1.0-beta6: - version "0.1.0-beta6" - resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta6.tgz#9b4e862be8928ef455a667745bea479665db6c6b" - integrity sha512-tkVU5wCfBFjXwfOvcbMHoLoMDANztkwSREiKyu2R059kEF+sP67Z33HzxVCXUWFuCmutcx40xR2O0BK68gXZlg== - "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"