diff --git a/src/addons/attach/Interfaces.ts b/src/addons/attach/Interfaces.ts deleted file mode 100644 index 4b269099..00000000 --- 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 e280b656..00000000 --- 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 2c8a5d4d..00000000 --- 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 b6f853be..00000000 --- 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 9e45068b..00000000 --- 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/attach/tsconfig.json b/src/addons/attach/tsconfig.json deleted file mode 100644 index 2f39102c..00000000 --- a/src/addons/attach/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "lib": [ - "dom", - "es6", - ], - "rootDir": ".", - "outDir": "../../../lib/addons/attach/", - "sourceMap": true, - "removeComments": true, - "declaration": true - }, - "include": [ - "**/*.ts", - "../../../typings/xterm.d.ts" - ] -} diff --git a/src/addons/fullscreen/fullscreen.css b/src/addons/fullscreen/fullscreen.css deleted file mode 100644 index 60e8c511..00000000 --- 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 6d41bdfd..00000000 --- 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 083c00c2..00000000 --- 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 fdaf6880..00000000 --- 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 0c74c25c..00000000 --- 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 872537ea..00000000 --- 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/SearchHelper.ts b/src/addons/search/SearchHelper.ts deleted file mode 100644 index e23b14a1..00000000 --- a/src/addons/search/SearchHelper.ts +++ /dev/null @@ -1,344 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { ISearchHelper, ISearchAddonTerminal, ISearchOptions, ISearchResult } from './Interfaces'; -import { IDisposable } from 'xterm'; - -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 { - /** - * translateBufferLineToStringWithWrap is a fairly expensive call. - * We memoize the calls into an array that has a time based ttl. - * _linesCache is also invalidated when the terminal cursor moves. - */ - private _linesCache: string[] = null; - private _linesCacheTimeoutId = 0; - private _cursorMoveListener: IDisposable | undefined; - private _resizeListener: IDisposable | undefined; - - constructor(private _terminal: ISearchAddonTerminal) { - this._destroyLinesCache = this._destroyLinesCache.bind(this); - } - - /** - * 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. - */ - public findNext(term: string, searchOptions?: ISearchOptions): boolean { - const {incremental} = searchOptions; - let result: ISearchResult; - - if (!term || term.length === 0) { - this._terminal.clearSelection(); - return false; - } - - let startCol: number = 0; - let startRow = this._terminal.buffer.viewportY; - - if (this._terminal.hasSelection()) { - // Start from the selection end if there is a selection - // For incremental search, use existing row - const currentSelection = this._terminal.getSelectionPosition(); - startRow = incremental ? currentSelection.startRow : currentSelection.endRow; - startCol = incremental ? currentSelection.startColumn : currentSelection.endColumn; - } - - this._initLinesCache(); - - // A row that has isWrapped = false - let findingRow = startRow; - // index of beginning column that _findInLine need to scan. - let cumulativeCols = startCol; - // If startRow is wrapped row, scan for unwrapped row above. - // So we can start matching on wrapped line from long unwrapped line. - while (this._terminal.buffer.getLine(findingRow).isWrapped) { - findingRow--; - cumulativeCols += this._terminal.cols; - } - - // Search startRow - result = this._findInLine(term, findingRow, cumulativeCols, searchOptions); - - // Search from startRow + 1 to end - if (!result) { - - for (let y = startRow + 1; y < this._terminal.buffer.baseY + this._terminal.rows; y++) { - - // If the current line is wrapped line, increase index of column to ignore the previous scan - // Otherwise, reset beginning column index to zero with set new unwrapped line index - result = this._findInLine(term, y, 0, searchOptions); - if (result) { - break; - } - } - } - - // Search from the top to the startRow (search the whole startRow again in - // case startCol > 0) - if (!result) { - for (let y = 0; y < findingRow; y++) { - result = this._findInLine(term, y, 0, searchOptions); - if (result) { - break; - } - } - } - - // Set selection and scroll if a result was found - return this._selectResult(result); - } - - /** - * 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. - */ - public findPrevious(term: string, searchOptions?: ISearchOptions): boolean { - let result: ISearchResult; - - if (!term || term.length === 0) { - this._terminal.clearSelection(); - return false; - } - - const isReverseSearch = true; - let startRow = this._terminal.buffer.viewportY + this._terminal.rows - 1; - let startCol = this._terminal.cols; - - if (this._terminal.hasSelection()) { - // Start from the selection start if there is a selection - const currentSelection = this._terminal.getSelectionPosition(); - startRow = currentSelection.startRow; - startCol = currentSelection.startColumn; - } - - this._initLinesCache(); - - // Search startRow - result = this._findInLine(term, startRow, startCol, searchOptions, isReverseSearch); - - // Search from startRow - 1 to top - if (!result) { - // If the line is wrapped line, increase number of columns that is needed to be scanned - // Se we can scan on wrapped line from unwrapped line - let cumulativeCols = this._terminal.cols; - if (this._terminal.buffer.getLine(startRow).isWrapped) { - cumulativeCols += startCol; - } - for (let y = startRow - 1; y >= 0; y--) { - result = this._findInLine(term, y, cumulativeCols, searchOptions, isReverseSearch); - if (result) { - break; - } - // If the current line is wrapped line, increase scanning range, - // preparing for scanning on unwrapped line - if (this._terminal.buffer.getLine(y).isWrapped) { - cumulativeCols += this._terminal.cols; - } else { - cumulativeCols = this._terminal.cols; - } - } - } - - // Search from the bottom to startRow (search the whole startRow again in - // case startCol > 0) - if (!result) { - const searchFrom = this._terminal.buffer.baseY + this._terminal.rows - 1; - let cumulativeCols = this._terminal.cols; - for (let y = searchFrom; y >= startRow; y--) { - result = this._findInLine(term, y, cumulativeCols, searchOptions, isReverseSearch); - if (result) { - break; - } - if (this._terminal.buffer.getLine(y).isWrapped) { - cumulativeCols += this._terminal.cols; - } else { - cumulativeCols = this._terminal.cols; - } - } - } - - // Set selection and scroll if a result was found - return this._selectResult(result); - } - - /** - * Sets up a line cache with a ttl - */ - private _initLinesCache(): void { - if (!this._linesCache) { - this._linesCache = new Array(this._terminal.buffer.length); - this._cursorMoveListener = this._terminal.onCursorMove(() => this._destroyLinesCache()); - this._resizeListener = this._terminal.onResize(() => this._destroyLinesCache()); - } - - window.clearTimeout(this._linesCacheTimeoutId); - this._linesCacheTimeoutId = window.setTimeout(() => this._destroyLinesCache(), LINES_CACHE_TIME_TO_LIVE); - } - - private _destroyLinesCache(): void { - this._linesCache = null; - if (this._cursorMoveListener) { - this._cursorMoveListener.dispose(); - this._cursorMoveListener = undefined; - } - if (this._resizeListener) { - this._resizeListener.dispose(); - this._resizeListener = undefined; - } - if (this._linesCacheTimeoutId) { - window.clearTimeout(this._linesCacheTimeoutId); - this._linesCacheTimeoutId = 0; - } - } - - /** - * A found substring is a whole word if it doesn't have an alphanumeric character directly adjacent to it. - * @param searchIndex starting indext of the potential whole word substring - * @param line entire string in which the potential whole word was found - * @param term the substring that starts at searchIndex - */ - private _isWholeWord(searchIndex: number, line: string, term: string): boolean { - return (((searchIndex === 0) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex - 1]) !== -1)) && - (((searchIndex + term.length) === line.length) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex + term.length]) !== -1))); - } - - /** - * Searches a line for a search term. Takes the provided terminal line and searches the text line, which may contain - * subsequent terminal lines if the text is wrapped. If the provided line number is part of a wrapped text line that - * started on an earlier line then it is skipped since it will be properly searched when the terminal line that the - * text starts on is searched. - * @param term The search term. - * @param row The line to start the search from. - * @param col The column to start the search from. - * @param searchOptions Search options. - * @return The search result if it was found. - */ - protected _findInLine(term: string, row: number, col: number, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult { - - // Ignore wrapped lines, only consider on unwrapped line (first row of command string). - if (this._terminal.buffer.getLine(row).isWrapped) { - return; - } - let stringLine = this._linesCache ? this._linesCache[row] : void 0; - if (stringLine === void 0) { - stringLine = this.translateBufferLineToStringWithWrap(row, true); - if (this._linesCache) { - this._linesCache[row] = stringLine; - } - } - - const searchTerm = searchOptions.caseSensitive ? term : term.toLowerCase(); - const searchStringLine = searchOptions.caseSensitive ? stringLine : stringLine.toLowerCase(); - - let resultIndex = -1; - if (searchOptions.regex) { - const searchRegex = RegExp(searchTerm, 'g'); - let foundTerm: RegExpExecArray; - if (isReverseSearch) { - // This loop will get the resultIndex of the _last_ regex match in the range 0..col - while (foundTerm = searchRegex.exec(searchStringLine.slice(0, col))) { - resultIndex = searchRegex.lastIndex - foundTerm[0].length; - term = foundTerm[0]; - searchRegex.lastIndex -= (term.length - 1); - } - } else { - foundTerm = searchRegex.exec(searchStringLine.slice(col)); - if (foundTerm && foundTerm[0].length > 0) { - resultIndex = col + (searchRegex.lastIndex - foundTerm[0].length); - term = foundTerm[0]; - } - } - } else { - if (isReverseSearch) { - if (col - searchTerm.length >= 0) { - resultIndex = searchStringLine.lastIndexOf(searchTerm, col - searchTerm.length); - } - } else { - resultIndex = searchStringLine.indexOf(searchTerm, col); - } - } - - if (resultIndex >= 0) { - // Adjust the row number and search index if needed since a "line" of text can span multiple rows - if (resultIndex >= this._terminal.cols) { - row += Math.floor(resultIndex / this._terminal.cols); - resultIndex = resultIndex % this._terminal.cols; - } - if (searchOptions.wholeWord && !this._isWholeWord(resultIndex, searchStringLine, term)) { - return; - } - - const line = this._terminal.buffer.getLine(row); - - for (let i = 0; i < resultIndex; i++) { - const cell = line.getCell(i); - // Adjust the searchIndex to normalize emoji into single chars - const char = cell.char; - if (char.length > 1) { - resultIndex -= char.length - 1; - } - // Adjust the searchIndex for empty characters following wide unicode - // chars (eg. CJK) - const charWidth = cell.width; - if (charWidth === 0) { - resultIndex++; - } - } - return { - term, - col: resultIndex, - row - }; - } - } - /** - * Translates a buffer line to a string, including subsequent lines if they are wraps. - * Wide characters will count as two columns in the resulting string. This - * function is useful for getting the actual text underneath the raw selection - * position. - * @param line The line being translated. - * @param trimRight Whether to trim whitespace to the right. - */ - public translateBufferLineToStringWithWrap(lineIndex: number, trimRight: boolean): string { - let lineString = ''; - let lineWrapsToNext: boolean; - - do { - const nextLine = this._terminal.buffer.getLine(lineIndex + 1); - lineWrapsToNext = nextLine ? nextLine.isWrapped : false; - lineString += this._terminal.buffer.getLine(lineIndex).translateToString(!lineWrapsToNext && trimRight).substring(0, this._terminal.cols); - lineIndex++; - } while (lineWrapsToNext); - - return lineString; - } - - /** - * Selects and scrolls to a result. - * @param result The result to select. - * @return Whethera result was selected. - */ - private _selectResult(result: ISearchResult): boolean { - if (!result) { - this._terminal.clearSelection(); - return false; - } - this._terminal.select(result.col, result.row, result.term.length); - this._terminal.scrollLines(result.row - this._terminal.buffer.viewportY); - return true; - } -} diff --git a/src/addons/search/package.json b/src/addons/search/package.json deleted file mode 100644 index 552e9332..00000000 --- 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 262b475f..00000000 --- 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 c274f28a..00000000 --- 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 6a1611a5..00000000 --- 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 dd7b045c..00000000 --- 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 d6959592..00000000 --- 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 e46eafdf..00000000 --- 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 9895a07b..00000000 --- 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 e2e19445..00000000 --- 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 f200cab4..00000000 --- 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 9c4f1176..00000000 --- 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 da5569ab..00000000 --- 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/webLinks/webLinks.ts b/src/addons/webLinks/webLinks.ts deleted file mode 100644 index 8a0fec09..00000000 --- a/src/addons/webLinks/webLinks.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { Terminal, ILinkMatcherOptions } from 'xterm'; - -const protocolClause = '(https?:\\/\\/)'; -const domainCharacterSet = '[\\da-z\\.-]+'; -const negatedDomainCharacterSet = '[^\\da-z\\.-]+'; -const domainBodyClause = '(' + domainCharacterSet + ')'; -const tldClause = '([a-z\\.]{2,6})'; -const ipClause = '((\\d{1,3}\\.){3}\\d{1,3})'; -const localHostClause = '(localhost)'; -const portClause = '(:\\d{1,5})'; -const hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + '|' + localHostClause + ')' + portClause + '?'; -const pathCharacterSet = '(\\/[\\/\\w\\.\\-%~:+]*)*([^:"\'\\s])'; -const pathClause = '(' + pathCharacterSet + ')?'; -const queryStringHashFragmentCharacterSet = '[0-9\\w\\[\\]\\(\\)\\/\\?\\!#@$%&\'*+,:;~\\=\\.\\-]*'; -const queryStringClause = '(\\?' + queryStringHashFragmentCharacterSet + ')?'; -const hashFragmentClause = '(#' + queryStringHashFragmentCharacterSet + ')?'; -const negatedPathCharacterSet = '[^\\/\\w\\.\\-%]+'; -const bodyClause = hostClause + pathClause + queryStringClause + hashFragmentClause; -const start = '(?:^|' + negatedDomainCharacterSet + ')('; -const end = ')($|' + negatedPathCharacterSet + ')'; -const strictUrlRegex = new RegExp(start + protocolClause + bodyClause + end); - -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 function apply(terminalConstructor: typeof Terminal): void { - (terminalConstructor.prototype).webLinksInit = function (handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void { - webLinksInit(this, handler, options); - }; -} diff --git a/src/addons/zmodem/package.json b/src/addons/zmodem/package.json deleted file mode 100644 index 218130ab..00000000 --- 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 7d821b7c..00000000 --- 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 d0c7c5fb..00000000 --- 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 70fc6e98..00000000 --- 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/tsconfig.all.json b/tsconfig.all.json index e7e503b6..b2e74f03 100644 --- a/tsconfig.all.json +++ b/tsconfig.all.json @@ -6,12 +6,6 @@ { "path": "./addons/xterm-addon-attach/src" }, { "path": "./addons/xterm-addon-search/src" }, { "path": "./addons/xterm-addon-web-links/src" }, - { "path": "./src/addons/attach" }, - { "path": "./src/addons/fit" }, - { "path": "./src/addons/fullscreen" }, - { "path": "./src/addons/search" }, - { "path": "./src/addons/terminado" }, - { "path": "./src/addons/webLinks" }, - { "path": "./src/addons/zmodem" } + { "path": "./src/addons/fit" } ] }