diff --git a/.gitignore b/.gitignore index bf0c3d8ce..e8da2d469 100644 --- a/.gitignore +++ b/.gitignore @@ -19,10 +19,6 @@ fixtures/typings-test/*.js # Directories needed for code coverage /coverage/ -# Keep legacy files out of the repo, this can be removed when we merge v3 into master +# Keep bundled code out of Git dist/ -src/utils/TestUtils.ts -src/xterm.js - -# Keep the demo builds out of Git demo/dist/ diff --git a/.travis.yml b/.travis.yml index 7a37af1e7..c41ebf797 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ before_install: - npm install -g npm@5.1.0 env: matrix: + - NPM_COMMAND=tsc - NPM_COMMAND=lint - NPM_COMMAND=test notifications: diff --git a/README.md b/README.md index 730fc9af9..a5d34632b 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ computational environment for Jupyter, supporting interactive data science and s - [**rtty**](https://github.com/zhaojh329/rtty): A reverse proxy WebTTY. It is composed of the client and the server. - [**Pisth**](https://github.com/ColdGrub1384/Pisth): An SFTP and SSH client for iOS - [**abstruse**](https://github.com/bleenco/abstruse): Abstruse CI is a continuous integration platform based on Node.JS and Docker. +- [**Microsoft SQL Operations Studio**](https://github.com/Microsoft/sqlopsstudio): A data management tool that enables working with SQL Server, Azure SQL DB and SQL DW from Windows, macOS and Linux Do you use xterm.js in your application as well? Please [open a Pull Request](https://github.com/sourcelair/xterm.js/pulls) to include it here. We would love to have it in our list. diff --git a/fixtures/typings-test/typings-test.ts b/fixtures/typings-test/typings-test.ts index 6761dcd54..7bbaf214b 100644 --- a/fixtures/typings-test/typings-test.ts +++ b/fixtures/typings-test/typings-test.ts @@ -147,6 +147,7 @@ namespace methods_core { const r23: boolean = t.getOption('macOptionIsMeta'); const r24: string = t.getOption('fontWeight'); const r25: string = t.getOption('fontWeightBold'); + const r26: boolean = t.getOption('allowTransparency'); } { const t: Terminal = new Terminal(); @@ -167,6 +168,7 @@ namespace methods_core { t.setOption('popOnBell', true); t.setOption('screenKeys', true); t.setOption('useFlowControl', true); + t.setOption('allowTransparency', true); t.setOption('visualBell', true); t.setOption('colors', ['a', 'b']); t.setOption('letterSpacing', 1); diff --git a/package.json b/package.json index cf3df57be..ba988d613 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "lint": "tslint src/*.ts src/**/*.ts", "test": "gulp test", "build:docs": "jsdoc -c jsdoc.json", + "tsc": "tsc", "build": "gulp build", "prepublish": "npm run build", "coveralls": "gulp coveralls", diff --git a/src/Buffer.ts b/src/Buffer.ts index 462cde56d..7e34a23df 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -213,7 +213,10 @@ export class Buffer implements IBuffer { // needed here because some chars are 0 characters long (eg. after wide // chars) and some chars are longer than 1 characters long (eg. emojis). let startIndex = startCol; - endCol = endCol || line.length; + // Only set endCol to the line length when it is null. 0 is a valid column. + if (endCol === null) { + endCol = line.length; + } let endIndex = endCol; for (let i = 0; i < line.length; i++) { diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 383427b97..3c927839e 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -11,6 +11,7 @@ import { CircularList } from './utils/CircularList'; import { EventEmitter } from './EventEmitter'; import { SelectionModel } from './SelectionModel'; import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from './Buffer'; +import { AltClickHandler } from './handlers/AltClickHandler'; /** * The number of pixels the mouse needs to be above or below the viewport in @@ -28,6 +29,12 @@ const DRAG_SCROLL_MAX_SPEED = 15; */ const DRAG_SCROLL_INTERVAL = 50; +/** + * The maximum amount of time that can have elapsed for an alt click to move the + * cursor. + */ +const ALT_CLICK_MOVE_CURSOR_TIME = 500; + /** * A string containing all characters that are considered word separated by the * double click to select work logic. @@ -96,6 +103,8 @@ export class SelectionManager extends EventEmitter implements ISelectionManager private _mouseUpListener: EventListener; private _trimListener: (...args: any[]) => void; + private _mouseDownTimeStamp: number; + constructor( private _terminal: ITerminal, private _charMeasure: CharMeasure @@ -317,6 +326,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager * @param event The mousedown event. */ public onMouseDown(event: MouseEvent): void { + this._mouseDownTimeStamp = event.timeStamp; // If we have selection, we want the context menu on right click even if the // terminal is in mouse mode. if (event.button === 2 && this.hasSelection) { @@ -536,9 +546,13 @@ export class SelectionManager extends EventEmitter implements ISelectionManager * @param event The mouseup event. */ private _onMouseUp(event: MouseEvent): void { + let timeElapsed = event.timeStamp - this._mouseDownTimeStamp; + this._removeMouseDownListeners(); - if (this.hasSelection) { + if (this.selectionText.length <= 1 && timeElapsed < ALT_CLICK_MOVE_CURSOR_TIME) { + (new AltClickHandler(event, this._terminal)).move(); + } else if (this.hasSelection) { this._terminal.emit('selection'); } } diff --git a/src/Terminal.ts b/src/Terminal.ts index a894f8c09..6e501d03b 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -85,6 +85,7 @@ const DEFAULT_OPTIONS: ITerminalOptions = { cancelEvents: false, disableStdin: false, useFlowControl: false, + allowTransparency: false, tabStopWidth: 8, theme: null // programFeatures: false, diff --git a/src/Types.ts b/src/Types.ts index f3e9bb941..da3cc9d2a 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -188,12 +188,14 @@ export interface ITerminal extends PublicTerminal, IElementAccessor, IBufferAcce isFocused: boolean; mouseHelper: IMouseHelper; bracketedPasteMode: boolean; + applicationCursor: boolean; /** * Emit the 'data' event and populate the given data. * @param data The data to populate in the event. */ handler(data: string): void; + send(data: string): void; scrollLines(disp: number, suppressScrollEvent?: boolean): void; cancel(ev: Event, force?: boolean): boolean | void; log(text: string): void; diff --git a/src/handlers/AltClickHandler.ts b/src/handlers/AltClickHandler.ts new file mode 100644 index 000000000..c9c51cbe5 --- /dev/null +++ b/src/handlers/AltClickHandler.ts @@ -0,0 +1,261 @@ +/** + * Copyright (c) 2018 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { ITerminal, ICircularList, LineData } from '../Types'; +import { C0 } from '../EscapeSequences'; + +enum Direction { + Up = 'A', + Down = 'B', + Right = 'C', + Left = 'D' +} + +export class AltClickHandler { + private _startRow: number; + private _startCol: number; + private _endRow: number; + private _endCol: number; + private _lines: ICircularList; + + constructor( + private _mouseEvent: MouseEvent, + private _terminal: ITerminal + ) { + this._lines = this._terminal.buffer.lines; + this._startCol = this._terminal.buffer.x; + this._startRow = this._terminal.buffer.y; + + [this._endCol, this._endRow] = this._terminal.mouseHelper.getCoords( + this._mouseEvent, + this._terminal.element, + this._terminal.charMeasure, + this._terminal.options.lineHeight, + this._terminal.cols, + this._terminal.rows, + false + ).map((coordinate: number) => { + return coordinate - 1; + }); + } + + /** + * Writes the escape sequences of arrows to the terminal + */ + public move(): void { + if (this._mouseEvent.altKey) { + this._terminal.send(this._arrowSequences()); + } + } + + /** + * Concatenates all the arrow sequences together. + * Resets the starting row to an unwrapped row, moves to the requested row, + * then moves to requested col. + */ + private _arrowSequences(): string { + return this._resetStartingRow() + + this._moveToRequestedRow() + + this._moveToRequestedCol(); + } + + /** + * If the initial position of the cursor is on a row that is wrapped, move the + * cursor up to the first row that is not wrapped to have accurate vertical + * positioning. + */ + private _resetStartingRow(): string { + let startRow = this._endRow - this._wrappedRowsForRow(this._endRow); + let endRow = this._endRow; + + if (this._moveToRequestedRow().length === 0) { + return ''; + } else { + return repeat(this._bufferLine( + this._startCol, this._startRow, this._startCol, + this._startRow - this._wrappedRowsForRow(this._startRow), false + ).length, this._sequence(Direction.Left)); + } + } + + /** + * Using the reset starting and ending row, move to the requested row, + * ignoring wrapped rows + */ + private _moveToRequestedRow(): string { + let startRow = this._startRow - this._wrappedRowsForRow(this._startRow); + let endRow = this._endRow - this._wrappedRowsForRow(this._endRow); + + let rowsToMove = Math.abs(startRow - endRow) - this._wrappedRowsCount(); + + return repeat(rowsToMove, this._sequence(this._verticalDirection())); + } + + /** + * Move to the requested col on the ending row + */ + private _moveToRequestedCol(): string { + let startRow; + if (this._moveToRequestedRow().length > 0) { + startRow = this._endRow - this._wrappedRowsForRow(this._endRow); + } else { + startRow = this._startRow; + } + + let endRow = this._endRow; + let direction = this._horizontalDirection(); + + return repeat(this._bufferLine( + this._startCol, startRow, this._endCol, endRow, + direction === Direction.Right + ).length, this._sequence(direction)); + } + + /** + * Utility functions + */ + + /** + * Calculates the number of wrapped rows between the unwrapped starting and + * ending rows. These rows need to ignored since the cursor skips over them. + */ + private _wrappedRowsCount(): number { + let wrappedRows = 0; + let startRow = this._startRow - this._wrappedRowsForRow(this._startRow); + let endRow = this._endRow - this._wrappedRowsForRow(this._endRow); + + for (let i = 0; i < Math.abs(startRow - endRow); i++) { + let direction = this._verticalDirection() === Direction.Up ? -1 : 1; + + if ((this._lines.get(startRow + (direction * i))).isWrapped) { + wrappedRows++; + } + } + + return wrappedRows; + } + + /** + * Calculates the number of wrapped rows that make up a given row. + * @param currentRow The row to determine how many wrapped rows make it up + */ + private _wrappedRowsForRow(currentRow: number): number { + let rowCount = 0; + let lineWraps = (this._lines.get(currentRow)).isWrapped; + + while (lineWraps && currentRow >= 0 && currentRow < this._terminal.rows) { + rowCount++; + currentRow--; + lineWraps = (this._lines.get(currentRow)).isWrapped; + } + + return rowCount; + } + + /** + * Direction determiners + */ + + /** + * Determines if the right or left arrow is needed + */ + private _horizontalDirection(): Direction { + let startRow; + if (this._moveToRequestedRow().length > 0) { + startRow = this._endRow - this._wrappedRowsForRow(this._endRow); + } else { + startRow = this._startRow; + } + + if ((this._startCol < this._endCol && + startRow <= this._endRow) || // down/right or same y/right + (this._startCol >= this._endCol && + startRow < this._endRow)) { // down/left or same y/left + return Direction.Right; + } else { + return Direction.Left; + } + } + + /** + * Determines if the up or down arrow is needed + */ + private _verticalDirection(): Direction { + if (this._startRow > this._endRow) { + return Direction.Up; + } else { + return Direction.Down; + } + } + + /** + * Constructs the string of chars in the buffer from a starting row and col + * to an ending row and col + * @param startCol The starting column position + * @param startRow The starting row position + * @param endCol The ending column position + * @param endRow The ending row position + * @param forward Direction to move + */ + private _bufferLine( + startCol: number, + startRow: number, + endCol: number, + endRow: number, + forward: boolean + ): string { + let currentCol = startCol; + let currentRow = startRow; + let bufferStr = ''; + + while (currentCol !== endCol || currentRow !== endRow) { + currentCol += forward ? 1 : -1; + + if (forward && currentCol > this._terminal.cols - 1) { + bufferStr += this._terminal.buffer.translateBufferLineToString( + currentRow, false, startCol, currentCol + ); + currentCol = 0; + startCol = 0; + currentRow++; + } else if (!forward && currentCol < 0) { + bufferStr += this._terminal.buffer.translateBufferLineToString( + currentRow, false, 0, startCol + 1 + ); + currentCol = this._terminal.cols - 1; + startCol = currentCol; + currentRow--; + } + } + + return bufferStr + this._terminal.buffer.translateBufferLineToString( + currentRow, false, startCol, currentCol + ); + } + + /** + * Constructs the escape sequence for clicking an arrow + * @param direction The direction to move + */ + private _sequence(direction: Direction): string { + const mod = this._terminal.applicationCursor ? 'O' : '['; + return C0.ESC + mod + direction; + } +} + +/** + * Returns a string repeated a given number of times + * Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat + * @param count The number of times to repeat the string + * @param string The string that is to be repeated + */ +function repeat(count: number, str: string): string { + count = Math.floor(count); + let rpt = ''; + for (let i = 0; i < count; i++) { + rpt += str; + } + return rpt; +} diff --git a/src/handlers/Clipboard.ts b/src/handlers/Clipboard.ts index fd2b3d779..035b5fff9 100644 --- a/src/handlers/Clipboard.ts +++ b/src/handlers/Clipboard.ts @@ -100,6 +100,7 @@ export function moveTextAreaUnderMouseCursor(ev: MouseEvent, textarea: HTMLTextA textarea.focus(); // Reset the terminal textarea's styling + // Timeout needs to be long enough for click event to be handled. setTimeout(() => { textarea.style.position = null; textarea.style.width = null; @@ -107,7 +108,7 @@ export function moveTextAreaUnderMouseCursor(ev: MouseEvent, textarea: HTMLTextA textarea.style.left = null; textarea.style.top = null; textarea.style.zIndex = null; - }, 4); + }, 200); } /** diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 20a41cfa3..9423f65d3 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -24,22 +24,25 @@ export abstract class BaseRenderLayer implements IRenderLayer { private _charAtlas: HTMLCanvasElement | ImageBitmap; constructor( - container: HTMLElement, + private _container: HTMLElement, id: string, zIndex: number, private _alpha: boolean, protected _colors: IColorSet ) { this._canvas = document.createElement('canvas'); - this._canvas.id = `xterm-${id}-layer`; + this._canvas.classList.add(`xterm-${id}-layer`); this._canvas.style.zIndex = zIndex.toString(); - this._ctx = this._canvas.getContext('2d', {alpha: _alpha}); - this._ctx.scale(window.devicePixelRatio, window.devicePixelRatio); + this._initCanvas(); + this._container.appendChild(this._canvas); + } + + private _initCanvas(): void { + this._ctx = this._canvas.getContext('2d', {alpha: this._alpha}); // Draw the background if this is an opaque layer - if (!_alpha) { + if (!this._alpha) { this.clearAll(); } - container.appendChild(this._canvas); } public onOptionsChanged(terminal: ITerminal): void {} @@ -53,6 +56,25 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._refreshCharAtlas(terminal, colorSet); } + protected setTransparency(terminal: ITerminal, alpha: boolean): void { + // Do nothing when alpha doesn't change + if (alpha === this._alpha) { + return; + } + + // Create new canvas and replace old one + const oldCanvas = this._canvas; + this._alpha = alpha; + // Cloning preserves properties + this._canvas = this._canvas.cloneNode(); + this._initCanvas(); + this._container.replaceChild(this._canvas, oldCanvas); + + // Regenerate char atlas and force a full redraw + this._refreshCharAtlas(terminal, this._colors); + this.onGridChanged(terminal, 0, terminal.rows - 1); + } + /** * Refreshes the char atlas, aquiring a new one if necessary. * @param terminal The terminal. @@ -63,7 +85,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { return; } this._charAtlas = null; - const result = acquireCharAtlas(terminal, this._colors, this._scaledCharWidth, this._scaledCharHeight); + const result = acquireCharAtlas(terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight); if (result instanceof HTMLCanvasElement) { this._charAtlas = result; } else { diff --git a/src/renderer/CharAtlas.ts b/src/renderer/CharAtlas.ts index 05cf72014..ff8990b30 100644 --- a/src/renderer/CharAtlas.ts +++ b/src/renderer/CharAtlas.ts @@ -17,6 +17,7 @@ interface ICharAtlasConfig { fontWeightBold: string; scaledCharWidth: number; scaledCharHeight: number; + allowTransparency: boolean; colors: IColorSet; } @@ -83,7 +84,8 @@ export function acquireCharAtlas(terminal: ITerminal, colors: IColorSet, scaledC background: colors.background, foreground: colors.foreground, ansiColors: colors.ansi, - devicePixelRatio: window.devicePixelRatio + devicePixelRatio: window.devicePixelRatio, + allowTransparency: terminal.options.allowTransparency }; const newEntry: ICharAtlasCacheEntry = { @@ -111,6 +113,7 @@ function generateConfig(scaledCharWidth: number, scaledCharHeight: number, termi fontSize: terminal.options.fontSize, fontWeight: terminal.options.fontWeight, fontWeightBold: terminal.options.fontWeightBold, + allowTransparency: terminal.options.allowTransparency, colors: clonedColors }; } @@ -125,6 +128,7 @@ function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean { a.fontSize === b.fontSize && a.fontWeight === b.fontWeight && a.fontWeightBold === b.fontWeightBold && + a.allowTransparency === b.allowTransparency && a.scaledCharWidth === b.scaledCharWidth && a.scaledCharHeight === b.scaledCharHeight && a.colors.foreground === b.colors.foreground && diff --git a/src/renderer/ColorManager.ts b/src/renderer/ColorManager.ts index b45c86469..90ef0431d 100644 --- a/src/renderer/ColorManager.ts +++ b/src/renderer/ColorManager.ts @@ -86,7 +86,7 @@ export class ColorManager implements IColorManager { */ public setTheme(theme: ITheme): void { this.colors.foreground = theme.foreground || DEFAULT_FOREGROUND; - this.colors.background = this._validateColor(theme.background, DEFAULT_BACKGROUND); + this.colors.background = theme.background || DEFAULT_BACKGROUND; this.colors.cursor = theme.cursor || DEFAULT_CURSOR; this.colors.cursorAccent = theme.cursorAccent || DEFAULT_CURSOR_ACCENT; this.colors.selection = theme.selection || DEFAULT_SELECTION; @@ -107,20 +107,4 @@ export class ColorManager implements IColorManager { this.colors.ansi[14] = theme.brightCyan || DEFAULT_ANSI_COLORS[14]; this.colors.ansi[15] = theme.brightWhite || DEFAULT_ANSI_COLORS[15]; } - - private _validateColor(color: string, fallback: string): string { - if (!color) { - return fallback; - } - if (color.length === 7 && color.charAt(0) === '#') { - return color; - } - if (color.length === 4 && color.charAt(0) === '#') { - const r = color.charAt(1); - const g = color.charAt(2); - const b = color.charAt(3); - return `#${r}${r}${g}${g}${b}${b}`; - } - return fallback; - } } diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 8b9f5006e..11c247332 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -36,8 +36,9 @@ export class Renderer extends EventEmitter implements IRenderer { if (theme) { this.colorManager.setTheme(theme); } + this._renderLayers = [ - new TextRenderLayer(this._terminal.element, 0, this.colorManager.colors), + new TextRenderLayer(this._terminal.element, 0, this.colorManager.colors, this._terminal.options.allowTransparency), new SelectionRenderLayer(this._terminal.element, 1, this.colorManager.colors), new LinkRenderLayer(this._terminal.element, 2, this.colorManager.colors, this._terminal), new CursorRenderLayer(this._terminal.element, 3, this.colorManager.colors) diff --git a/src/renderer/TextRenderLayer.ts b/src/renderer/TextRenderLayer.ts index 3c01cea3b..a2ab9f19b 100644 --- a/src/renderer/TextRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -22,8 +22,8 @@ export class TextRenderLayer extends BaseRenderLayer { private _characterFont: string; private _characterOverlapCache: { [key: string]: boolean } = {}; - constructor(container: HTMLElement, zIndex: number, colors: IColorSet) { - super(container, 'text', zIndex, false, colors); + constructor(container: HTMLElement, zIndex: number, colors: IColorSet, alpha: boolean) { + super(container, 'text', zIndex, alpha, colors); this._state = new GridCache(); } @@ -190,6 +190,10 @@ export class TextRenderLayer extends BaseRenderLayer { } } + public onOptionsChanged(terminal: ITerminal): void { + this.setTransparency(terminal, terminal.options.allowTransparency); + } + /** * Whether a character is overlapping to the next cell. */ diff --git a/src/shared/CharAtlasGenerator.ts b/src/shared/CharAtlasGenerator.ts index 9ae9f4b31..96cf6cc63 100644 --- a/src/shared/CharAtlasGenerator.ts +++ b/src/shared/CharAtlasGenerator.ts @@ -26,6 +26,7 @@ export interface ICharAtlasRequest { foreground: string; ansiColors: string[]; devicePixelRatio: number; + allowTransparency: boolean; } export const CHAR_ATLAS_CELL_SPACING = 1; @@ -43,7 +44,7 @@ export function generateCharAtlas(context: Window, canvasFactory: (width: number /*255 ascii chars*/255 * cellWidth, (/*default+default bold*/2 + /*0-15*/16) * cellHeight ); - const ctx = canvas.getContext('2d', {alpha: false}); + const ctx = canvas.getContext('2d', {alpha: request.allowTransparency}); ctx.fillStyle = request.background; ctx.fillRect(0, 0, canvas.width, canvas.height); diff --git a/src/utils/TestUtils.test.ts b/src/utils/TestUtils.test.ts index 0744cd142..d53c8c58b 100644 --- a/src/utils/TestUtils.test.ts +++ b/src/utils/TestUtils.test.ts @@ -70,6 +70,9 @@ export class MockTerminal implements ITerminal { write(data: string): void { throw new Error('Method not implemented.'); } + send(data: string): void { + throw new Error('Method not implemented.'); + } bracketedPasteMode: boolean; mouseHelper: IMouseHelper; renderer: IRenderer; @@ -93,6 +96,7 @@ export class MockTerminal implements ITerminal { scrollback: number; buffers: IBufferSet; buffer: IBuffer; + applicationCursor: boolean; handler(data: string): void { throw new Error('Method not implemented.'); } diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index dbd1eebc6..0b35edf11 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -17,6 +17,12 @@ declare module 'xterm' { * An object containing start up options for the terminal. */ export interface ITerminalOptions { + /** + * Whether background should support non-opaque color. It must be set before + * executing open() method and can't be changed later without excuting it again. + * Warning: Enabling this option can reduce performances somewhat. + */ + allowTransparency?: boolean; /** * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). */ @@ -421,7 +427,7 @@ declare module 'xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; + getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -472,7 +478,7 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; + setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key.