From 72a557cc1a2bbb62805dfb1e91dc5ee298e1620d Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 1 Sep 2021 07:59:45 +0000 Subject: [PATCH 01/35] Make options available in terminal --- src/browser/Terminal.ts | 2 +- src/browser/public/Terminal.ts | 3 ++ src/common/CoreTerminal.ts | 3 +- src/common/TestUtils.test.ts | 6 +-- src/common/Types.d.ts | 1 + src/common/services/OptionsService.ts | 75 +++++++++++++++------------ src/common/services/Services.ts | 49 ++++------------- typings/xterm.d.ts | 5 ++ 8 files changed, 65 insertions(+), 79 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index ebe755bc..b487a18f 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -152,7 +152,7 @@ export class Terminal extends CoreTerminal implements ITerminal { * @alias module:xterm/src/xterm */ constructor( - options: ITerminalOptions = {} + options: Partial = {} ) { super(options); diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index a76b1a22..761c27e6 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -89,6 +89,9 @@ export class Terminal implements ITerminalApi { wraparoundMode: m.wraparound }; } + public get options(): ITerminalOptions { + return this._core.options; + } public blur(): void { this._core.blur(); } diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index 96a4b53d..d0f2f8f2 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -86,9 +86,10 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { public get cols(): number { return this._bufferService.cols; } public get rows(): number { return this._bufferService.rows; } public get buffers(): IBufferSet { return this._bufferService.buffers; } + public get options(): ITerminalOptions { return this.optionsService.options; } constructor( - options: ITerminalOptions + options: Partial ) { super(); diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 52fe00d0..1d38df21 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IPartialTerminalOptions, IDirtyRowService, ICoreMouseService, ICharsetService, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum } from 'common/services/Services'; +import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IDirtyRowService, ICoreMouseService, ICharsetService, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum } from 'common/services/Services'; import { IEvent, EventEmitter } from 'common/EventEmitter'; import { clone } from 'common/Clone'; import { DEFAULT_OPTIONS } from 'common/services/OptionsService'; @@ -122,10 +122,10 @@ export class MockOptionsService implements IOptionsService { public serviceBrand: any; public options: ITerminalOptions = clone(DEFAULT_OPTIONS); public onOptionChange: IEvent = new EventEmitter().event; - constructor(testOptions?: IPartialTerminalOptions) { + constructor(testOptions?: Partial) { if (testOptions) { for (const key of Object.keys(testOptions)) { - this.options[key] = (testOptions as any)[key]; + this.options[key] = testOptions[key]; } } } diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 78e2e62d..88497e4a 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -16,6 +16,7 @@ export interface ICoreTerminal { optionsService: IOptionsService; unicodeService: IUnicodeService; buffers: IBufferSet; + options: ITerminalOptions; registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise): IDisposable; registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise): IDisposable; registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise): IDisposable; diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 5add8283..e1838b5d 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -3,10 +3,9 @@ * @license MIT */ -import { IOptionsService, ITerminalOptions, IPartialTerminalOptions, FontWeight } from 'common/services/Services'; +import { IOptionsService, ITerminalOptions, FontWeight } from 'common/services/Services'; import { EventEmitter, IEvent } from 'common/EventEmitter'; import { isMac } from 'common/Platform'; -import { clone } from 'common/Clone'; // Source: https://freesound.org/people/altemark/sounds/45759/ // This sound is released under the Creative Commons Attribution 3.0 Unported @@ -14,15 +13,14 @@ import { clone } from 'common/Clone'; // made, apart from the conversion to base64. export const DEFAULT_BELL_SOUND = 'data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjMyLjEwNAAAAAAAAAAAAAAA//tQxAADB8AhSmxhIIEVCSiJrDCQBTcu3UrAIwUdkRgQbFAZC1CQEwTJ9mjRvBA4UOLD8nKVOWfh+UlK3z/177OXrfOdKl7pyn3Xf//WreyTRUoAWgBgkOAGbZHBgG1OF6zM82DWbZaUmMBptgQhGjsyYqc9ae9XFz280948NMBWInljyzsNRFLPWdnZGWrddDsjK1unuSrVN9jJsK8KuQtQCtMBjCEtImISdNKJOopIpBFpNSMbIHCSRpRR5iakjTiyzLhchUUBwCgyKiweBv/7UsQbg8isVNoMPMjAAAA0gAAABEVFGmgqK////9bP/6XCykxBTUUzLjEwMKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'; -// TODO: Freeze? -export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({ +export const DEFAULT_OPTIONS: Readonly = { cols: 80, rows: 24, cursorBlink: false, cursorStyle: 'block', cursorWidth: 1, customGlyphs: true, - bellSound: DEFAULT_BELL_SOUND, + bellSound: DEFAULT_BELL_SOUND, bellStyle: 'none', drawBoldTextInBrightColors: true, fastScrollModifier: 'alt', @@ -55,7 +53,7 @@ export const DEFAULT_OPTIONS: ITerminalOptions = Object.freeze({ convertEol: false, termName: 'xterm', cancelEvents: false -}); +}; const FONT_WEIGHT_OPTIONS: Extract[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']; @@ -67,45 +65,57 @@ const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows']; export class OptionsService implements IOptionsService { public serviceBrand: any; + private _options: any; public options: ITerminalOptions; private _onOptionChange = new EventEmitter(); public get onOptionChange(): IEvent { return this._onOptionChange.event; } - constructor(options: IPartialTerminalOptions) { - this.options = clone(DEFAULT_OPTIONS); - for (const k of Object.keys(options)) { - if (k in this.options) { + constructor(options: Partial) { + this.options = { ... DEFAULT_OPTIONS }; + for (const key in options) { + if (key in this.options) { try { - const newValue = options[k as keyof IPartialTerminalOptions] as any; - this.options[k] = this._sanitizeAndValidateOption(k, newValue); + const newValue = options[key]; + this.options[key] = this._sanitizeAndValidateOption(key, newValue); } catch (e) { console.error(e); } } } + + this._options = {}; + for (const propName in this.options) { + const privatePropName = `_${propName}`; + this._options[privatePropName] = this.options[propName]; + Object.defineProperty(this.options, propName, { + get: () => { + if (!(propName in DEFAULT_OPTIONS)) { + throw new Error(`No option with key "${propName}"`); + } + return this._options[privatePropName]; + }, + set: (value: any) => { + if (!(propName in DEFAULT_OPTIONS)) { + throw new Error('No option with key "' + propName + '"'); + } + if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { + throw new Error(`Option "${propName}" can only be set in the constructor`); + } + + value = this._sanitizeAndValidateOption(propName, value); + // Don't fire an option change event if they didn't change + if (this._options[privatePropName] !== value) { + this._options[privatePropName] = value; + this._onOptionChange.fire(propName); + } + } + }); + } } public setOption(key: string, value: any): void { - if (!(key in DEFAULT_OPTIONS)) { - throw new Error('No option with key "' + key + '"'); - } - if (CONSTRUCTOR_ONLY_OPTIONS.includes(key)) { - throw new Error(`Option "${key}" can only be set in the constructor`); - } - if (this.options[key] === value) { - return; - } - - value = this._sanitizeAndValidateOption(key, value); - - // Don't fire an option change event if they didn't change - if (this.options[key] === value) { - return; - } - this.options[key] = value; - this._onOptionChange.fire(key); } private _sanitizeAndValidateOption(key: string, value: any): any { @@ -128,7 +138,7 @@ export class OptionsService implements IOptionsService { break; case 'cursorWidth': value = Math.floor(value); - // Fall through for bounds check + // Fall through for bounds check case 'lineHeight': case 'tabStopWidth': if (value < 1) { @@ -155,9 +165,6 @@ export class OptionsService implements IOptionsService { } public getOption(key: string): any { - if (!(key in DEFAULT_OPTIONS)) { - throw new Error(`No option with key "${key}"`); - } return this.options[key]; } } diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 2190a0f8..c5bc2900 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -198,56 +198,27 @@ export enum LogLevelEnum { OFF = 4 } export type RendererType = 'dom' | 'canvas'; +export type BellStyle = 'none' | 'sound' /* | 'visual' | 'both' */; +export type CursorStyle = 'block' | 'underline' | 'bar'; +export type FastScrollModifier = 'alt' | 'ctrl' | 'shift'; -export interface IPartialTerminalOptions { - altClickMovesCursor?: boolean; - allowTransparency?: boolean; - bellSound?: string; - bellStyle?: 'none' | 'sound' /* | 'visual' | 'both' */; - cols?: number; - cursorBlink?: boolean; - cursorStyle?: 'block' | 'underline' | 'bar'; - cursorWidth?: number; - disableStdin?: boolean; - drawBoldTextInBrightColors?: boolean; - fastScrollModifier?: 'alt' | 'ctrl' | 'shift'; - fastScrollSensitivity?: number; - fontSize?: number; - fontFamily?: string; - fontWeight?: FontWeight; - fontWeightBold?: FontWeight; - letterSpacing?: number; - lineHeight?: number; - logLevel?: LogLevel; - macOptionIsMeta?: boolean; - macOptionClickForcesSelection?: boolean; - rendererType?: RendererType; - rightClickSelectsWord?: boolean; - rows?: number; - screenReaderMode?: boolean; - scrollback?: number; - scrollSensitivity?: number; - tabStopWidth?: number; - theme?: ITheme; - windowsMode?: boolean; - wordSeparator?: string; - windowOptions?: IWindowOptions; -} export interface ITerminalOptions { allowProposedApi: boolean; allowTransparency: boolean; altClickMovesCursor: boolean; bellSound: string; - bellStyle: 'none' | 'sound' /* | 'visual' | 'both' */; + bellStyle: BellStyle; + cancelEvents: boolean; cols: number; + convertEol: boolean; cursorBlink: boolean; - cursorStyle: 'block' | 'underline' | 'bar'; + cursorStyle: CursorStyle; cursorWidth: number; customGlyphs: boolean; disableStdin: boolean; drawBoldTextInBrightColors: boolean; - fastScrollModifier: 'alt' | 'ctrl' | 'shift' | undefined; + fastScrollModifier: FastScrollModifier | undefined; fastScrollSensitivity: number; fontSize: number; fontFamily: string; @@ -267,15 +238,13 @@ export interface ITerminalOptions { scrollback: number; scrollSensitivity: number; tabStopWidth: number; + termName: string; theme: ITheme; windowsMode: boolean; windowOptions: IWindowOptions; wordSeparator: string; [key: string]: any; - cancelEvents: boolean; - convertEol: boolean; - termName: string; } export interface ITheme { diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index ba2be988..2f31a164 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -635,6 +635,11 @@ declare module 'xterm' { */ readonly modes: IModes; + /** + * Get the terminal options + */ + readonly options: ITerminalOptions; + /** * Natural language strings that can be localized. */ From 99239e9160f963547dbbe040d9f12c18f939c141 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Thu, 9 Sep 2021 18:02:40 +0000 Subject: [PATCH 02/35] Allow modifying constructor only options --- src/common/CoreTerminal.ts | 2 +- src/common/TestUtils.test.ts | 2 ++ src/common/services/OptionsService.ts | 35 +++++++++++++++++++++++++-- src/common/services/Services.ts | 1 + 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/common/CoreTerminal.ts b/src/common/CoreTerminal.ts index d0f2f8f2..a5f78f66 100644 --- a/src/common/CoreTerminal.ts +++ b/src/common/CoreTerminal.ts @@ -86,7 +86,7 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal { public get cols(): number { return this._bufferService.cols; } public get rows(): number { return this._bufferService.rows; } public get buffers(): IBufferSet { return this._bufferService.buffers; } - public get options(): ITerminalOptions { return this.optionsService.options; } + public get options(): ITerminalOptions { return this.optionsService.publicOptions; } constructor( options: Partial diff --git a/src/common/TestUtils.test.ts b/src/common/TestUtils.test.ts index 1d38df21..014142ac 100644 --- a/src/common/TestUtils.test.ts +++ b/src/common/TestUtils.test.ts @@ -121,11 +121,13 @@ export class MockLogService implements ILogService { export class MockOptionsService implements IOptionsService { public serviceBrand: any; public options: ITerminalOptions = clone(DEFAULT_OPTIONS); + public publicOptions: ITerminalOptions = clone(DEFAULT_OPTIONS); public onOptionChange: IEvent = new EventEmitter().event; constructor(testOptions?: Partial) { if (testOptions) { for (const key of Object.keys(testOptions)) { this.options[key] = testOptions[key]; + this.publicOptions[key] = testOptions[key]; } } } diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index e1838b5d..ec1d13ad 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -72,7 +72,7 @@ export class OptionsService implements IOptionsService { public get onOptionChange(): IEvent { return this._onOptionChange.event; } constructor(options: Partial) { - this.options = { ... DEFAULT_OPTIONS }; + this.options = { ...DEFAULT_OPTIONS }; for (const key in options) { if (key in this.options) { try { @@ -88,6 +88,7 @@ export class OptionsService implements IOptionsService { for (const propName in this.options) { const privatePropName = `_${propName}`; this._options[privatePropName] = this.options[propName]; + Object.defineProperty(this.options, propName, { get: () => { if (!(propName in DEFAULT_OPTIONS)) { @@ -99,6 +100,35 @@ export class OptionsService implements IOptionsService { if (!(propName in DEFAULT_OPTIONS)) { throw new Error('No option with key "' + propName + '"'); } + + value = this._sanitizeAndValidateOption(propName, value); + // Don't fire an option change event if they didn't change + if (this._options[privatePropName] !== value) { + this._options[privatePropName] = value; + this._onOptionChange.fire(propName); + } + } + }); + } + } + + public get publicOptions(): ITerminalOptions { + const publicOptions = { ... this.options }; + for (const propName in CONSTRUCTOR_ONLY_OPTIONS) { + const privatePropName = `_${propName}`; + Object.defineProperty(publicOptions, propName, { + get: () => { + if (!(propName in DEFAULT_OPTIONS)) { + throw new Error(`No option with key "${propName}"`); + } + return this._options[privatePropName]; + }, + set: (value: any) => { + if (!(propName in DEFAULT_OPTIONS)) { + throw new Error('No option with key "' + propName + '"'); + } + // Throw an error if any constructor only option is modified + // from terminal.options if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { throw new Error(`Option "${propName}" can only be set in the constructor`); } @@ -112,6 +142,7 @@ export class OptionsService implements IOptionsService { } }); } + return publicOptions; } public setOption(key: string, value: any): void { @@ -138,7 +169,7 @@ export class OptionsService implements IOptionsService { break; case 'cursorWidth': value = Math.floor(value); - // Fall through for bounds check + // Fall through for bounds check case 'lineHeight': case 'tabStopWidth': if (value < 1) { diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index c5bc2900..5124260a 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -181,6 +181,7 @@ export interface IOptionsService { serviceBrand: undefined; readonly options: ITerminalOptions; + readonly publicOptions: ITerminalOptions; readonly onOptionChange: IEvent; From c186fbeafcc907bb2e6af80c4485a255b8c4e778 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 15 Sep 2021 05:04:11 -0700 Subject: [PATCH 03/35] Add exclude mode/alt buffer options to serialize addon Fixes #3472 --- .../src/SerializeAddon.ts | 23 +++++++++++---- .../test/SerializeAddon.api.ts | 4 +-- .../typings/xterm-addon-serialize.d.ts | 29 +++++++++++++++---- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index a54b4325..d692c818 100644 --- a/addons/xterm-addon-serialize/src/SerializeAddon.ts +++ b/addons/xterm-addon-serialize/src/SerializeAddon.ts @@ -433,26 +433,37 @@ export class SerializeAddon implements ITerminalAddon { return content; } - public serialize(scrollback?: number): string { + public serialize(options?: ISerializeOptions): string { // TODO: Add combinedData support if (!this._terminal) { throw new Error('Cannot use addon until it has been loaded'); } // Normal buffer - let content = this._serializeBuffer(this._terminal, this._terminal.buffer.normal, scrollback); + let content = this._serializeBuffer(this._terminal, this._terminal.buffer.normal, options?.scrollback); // Alternate buffer - if (this._terminal.buffer.active.type === 'alternate') { - const alternativeScreenContent = this._serializeBuffer(this._terminal, this._terminal.buffer.alternate, undefined); - content += `\u001b[?1049h\u001b[H${alternativeScreenContent}`; + if (!options?.excludeAltBuffer) { + if (this._terminal.buffer.active.type === 'alternate') { + const alternativeScreenContent = this._serializeBuffer(this._terminal, this._terminal.buffer.alternate, undefined); + content += `\u001b[?1049h\u001b[H${alternativeScreenContent}`; + } } // Modes - content += this._serializeModes(this._terminal); + if (!options?.excludeModes) { + content += this._serializeModes(this._terminal); + } return content; } public dispose(): void { } } + + +interface ISerializeOptions { + scrollback?: number; + excludeModes?: boolean; + excludeAltBuffer?: boolean; +} diff --git a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts index bb66f37b..c8593b72 100644 --- a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts +++ b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts @@ -146,7 +146,7 @@ describe('SerializeAddon', () => { const cols = 10; const lines = newArray((index: number) => digitsString(cols, index), rows); await writeSync(page, lines.join('\\r\\n')); - assert.equal(await page.evaluate(`serializeAddon.serialize(${halfScrollback});`), lines.slice(halfScrollback, rows).join('\r\n')); + assert.equal(await page.evaluate(`serializeAddon.serialize({ scrollback: ${halfScrollback} });`), lines.slice(halfScrollback, rows).join('\r\n')); }); it('serialize 0 rows of scrollback', async function(): Promise { @@ -154,7 +154,7 @@ describe('SerializeAddon', () => { const cols = 10; const lines = newArray((index: number) => digitsString(cols, index), rows); await writeSync(page, lines.join('\\r\\n')); - assert.equal(await page.evaluate(`serializeAddon.serialize(0);`), lines.slice(rows - 10, rows).join('\r\n')); + assert.equal(await page.evaluate(`serializeAddon.serialize({ scrollback: 0 });`), lines.slice(rows - 10, rows).join('\r\n')); }); it('serialize all rows of content with color16', async function(): Promise { diff --git a/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts b/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts index b55ee303..a29dbb28 100644 --- a/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts +++ b/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts @@ -7,14 +7,14 @@ import { Terminal, ITerminalAddon } from 'xterm'; declare module 'xterm-addon-serialize' { /** - * An xterm.js addon that enables web links. + * An xterm.js addon that enables serialization of terminal contents. */ export class SerializeAddon implements ITerminalAddon { constructor(); /** - * Activates the addon + * Activates the addon. * @param terminal The terminal the addon is being loaded in. */ public activate(terminal: Terminal): void; @@ -24,15 +24,32 @@ declare module 'xterm-addon-serialize' { * the state. The cursor will also be positioned to the correct cell. When restoring a terminal * it is best to do before `Terminal.open` is called to avoid wasting CPU cycles rendering * incomplete frames. - * @param scrollback The number of rows in scrollback buffer to serialize, starting from the - * bottom of the scrollback buffer. This defaults to the all available rows in the scrollback - * buffer. + * @param options Custom options to allow control over what gets serialized. */ - public serialize(scrollback?: number): string; + public serialize(options?: ISerializeOptions): string; /** * Disposes the addon. */ public dispose(): void; } + + export interface ISerializeOptions { + /** + * The number of rows in the scrollback buffer to serialize, starting from the bottom of the + * scrollback buffer. When not specified, all available rows in the scrollback buffer will be + * serialized. + */ + scrollback?: number; + + /** + * Whether to exclude the terminal modes from the serialization. False by default. + */ + excludeModes?: boolean; + + /** + * Whether to exclude the alt buffer from the serialization. False by default. + */ + excludeAltBuffer?: boolean; + } } From 6493edcddf2b987afd927ad50a642b0abafb5b46 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 15 Sep 2021 05:40:46 -0700 Subject: [PATCH 04/35] Add new serialize option tests --- .../xterm-addon-serialize/test/SerializeAddon.api.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts index c8593b72..5fc1bfaf 100644 --- a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts +++ b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts @@ -157,6 +157,18 @@ describe('SerializeAddon', () => { assert.equal(await page.evaluate(`serializeAddon.serialize({ scrollback: 0 });`), lines.slice(rows - 10, rows).join('\r\n')); }); + it('serialize exclude modes', async () => { + await writeSync(page, 'before\\x1b[?1hafter'); + assert.equal(await page.evaluate(`serializeAddon.serialize();`), 'beforeafter\x1b[?1h'); + assert.equal(await page.evaluate(`serializeAddon.serialize({ excludeModes: true });`), 'beforeafter'); + }); + + it('serialize exclude alt buffer', async () => { + await writeSync(page, 'normal\\x1b[?1049h\\x1b[Halt'); + assert.equal(await page.evaluate(`serializeAddon.serialize();`), 'normal\x1b[?1049h\x1b[Halt'); + assert.equal(await page.evaluate(`serializeAddon.serialize({ excludeAltBuffer: true });`), 'normal'); + }); + it('serialize all rows of content with color16', async function(): Promise { const cols = 10; const color16 = [ From 5188633458464a43f930be5319350ef2f0cd68ec Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 15 Sep 2021 17:39:39 +0000 Subject: [PATCH 05/35] Update npmignore files --- .npmignore | 33 ++------------------- addons/xterm-addon-attach/.npmignore | 19 +++++++++---- addons/xterm-addon-fit/.npmignore | 19 +++++++++---- addons/xterm-addon-ligatures/.npmignore | 38 ++----------------------- addons/xterm-addon-search/.npmignore | 19 +++++++++---- addons/xterm-addon-serialize/.npmignore | 19 +++++++++---- addons/xterm-addon-unicode11/.npmignore | 19 +++++++++---- addons/xterm-addon-web-links/.npmignore | 19 +++++++++---- addons/xterm-addon-webgl/.npmignore | 21 +++++++++----- headless/.npmignore | 18 ++++++++---- 10 files changed, 115 insertions(+), 109 deletions(-) diff --git a/.npmignore b/.npmignore index da489720..71cc5e81 100644 --- a/.npmignore +++ b/.npmignore @@ -2,10 +2,6 @@ * !*/ -# Whitelist - entries to be included must be negated with "!" -!*.js -!*.json - # Whitelist - css/ !css/**/*.css @@ -23,34 +19,9 @@ !lib/**/*.css -# Whitelist - src/ -!src/**/*.ts -!src/**/*.d.ts - -!src/**/*.js -!src/**/*.js.map - -!src/**/*.css - # Whitelist - typings/ !typings/*.d.ts # Blacklist - (normal behavior) these will override any whitelist -*.d.ts.map -*.test.ts -*.test.d.ts -*.test.js -*.test.js.map -lib/test/ -webpack.config.js - -docs/ -/.idea/ -.vscode/ -bin/ -build/ -fixtures/ -demo/ -.devcontainer/ -out/ -addons/ +headless/ +typings/xterm-headless.d.ts diff --git a/addons/xterm-addon-attach/.npmignore b/addons/xterm-addon-attach/.npmignore index 1c794445..fc460879 100644 --- a/addons/xterm-addon-attach/.npmignore +++ b/addons/xterm-addon-attach/.npmignore @@ -1,5 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/addons/xterm-addon-fit/.npmignore b/addons/xterm-addon-fit/.npmignore index 1c794445..fc460879 100644 --- a/addons/xterm-addon-fit/.npmignore +++ b/addons/xterm-addon-fit/.npmignore @@ -1,5 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/addons/xterm-addon-ligatures/.npmignore b/addons/xterm-addon-ligatures/.npmignore index 9f4fec9a..fc460879 100644 --- a/addons/xterm-addon-ligatures/.npmignore +++ b/addons/xterm-addon-ligatures/.npmignore @@ -2,47 +2,13 @@ * !*/ -# Whitelist - entries to be included must be negated with "!" -!*.js -!*.json - # Whitelist - lib/ !lib/**/*.d.ts !lib/**/*.js !lib/**/*.js.map -# Whitelist - out/ -!out/**/*.d.ts - -!out/**/*.js -!out/**/*.js.map - -# Whitelist - src/ -!src/**/*.ts -!src/**/*.d.ts - -!src/**/*.js -!src/**/*.js.map +!lib/**/*.css # Whitelist - typings/ -!typings/**/*.d.ts - -# Blacklist - (normal behavior) these will override any whitelist -*.test.ts -*.test.d.ts -*.test.js -*.test.js.map - -docs/ -/.idea/ -.vscode/ -coverage/ -.nyc_output/ -fonts/ - -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +!typings/*.d.ts diff --git a/addons/xterm-addon-search/.npmignore b/addons/xterm-addon-search/.npmignore index 1c794445..fc460879 100644 --- a/addons/xterm-addon-search/.npmignore +++ b/addons/xterm-addon-search/.npmignore @@ -1,5 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/addons/xterm-addon-serialize/.npmignore b/addons/xterm-addon-serialize/.npmignore index 1c794445..fc460879 100644 --- a/addons/xterm-addon-serialize/.npmignore +++ b/addons/xterm-addon-serialize/.npmignore @@ -1,5 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/addons/xterm-addon-unicode11/.npmignore b/addons/xterm-addon-unicode11/.npmignore index 1c794445..fc460879 100644 --- a/addons/xterm-addon-unicode11/.npmignore +++ b/addons/xterm-addon-unicode11/.npmignore @@ -1,5 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/addons/xterm-addon-web-links/.npmignore b/addons/xterm-addon-web-links/.npmignore index 1c794445..fc460879 100644 --- a/addons/xterm-addon-web-links/.npmignore +++ b/addons/xterm-addon-web-links/.npmignore @@ -1,5 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/addons/xterm-addon-webgl/.npmignore b/addons/xterm-addon-webgl/.npmignore index 5e5c6068..fc460879 100644 --- a/addons/xterm-addon-webgl/.npmignore +++ b/addons/xterm-addon-webgl/.npmignore @@ -1,7 +1,14 @@ -**/*.api.js -**/*.api.ts -tsconfig.json -.yarnrc -webpack.config.js -out-test/ -test/ +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ + +# Whitelist - lib/ +!lib/**/*.d.ts + +!lib/**/*.js +!lib/**/*.js.map + +!lib/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts diff --git a/headless/.npmignore b/headless/.npmignore index 83e9f201..20a02782 100644 --- a/headless/.npmignore +++ b/headless/.npmignore @@ -1,6 +1,14 @@ -# Include -!typings/*.d.ts -!lib-headless/ +# Blacklist - exclude everything except npm defaults such as LICENSE, etc +* +!*/ -# Exclude -test/ +# Whitelist - lib-headless/ +!lib-headless/**/*.d.ts + +!lib-headless/**/*.js +!lib-headless/**/*.js.map + +!lib-headless/**/*.css + +# Whitelist - typings/ +!typings/*.d.ts From 9c4a08a55a42200846c165f98ac45a7bf22a5e05 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 22 Sep 2021 08:41:57 +0000 Subject: [PATCH 06/35] devcontainer mocha --- .devcontainer/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5992027c..9aec3a02 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,6 +4,7 @@ "appPort": 3000, "extensions": [ "dbaeumer.vscode-eslint", - "editorconfig.editorconfig" + "editorconfig.editorconfig", + "hbenl.vscode-mocha-test-adapter" ] } From 2e4e29ad73174757632be34fb0d0c11377e3e803 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 22 Sep 2021 08:47:36 +0000 Subject: [PATCH 07/35] Support strikethrough in serialize addon --- addons/xterm-addon-serialize/src/SerializeAddon.ts | 6 ++++-- typings/xterm-headless.d.ts | 12 +++++++----- typings/xterm.d.ts | 10 ++++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index a54b4325..41195a7e 100644 --- a/addons/xterm-addon-serialize/src/SerializeAddon.ts +++ b/addons/xterm-addon-serialize/src/SerializeAddon.ts @@ -72,7 +72,8 @@ function equalFlags(cell1: IBufferCell, cell2: IBufferCell): boolean { && cell1.isBlink() === cell2.isBlink() && cell1.isInvisible() === cell2.isInvisible() && cell1.isItalic() === cell2.isItalic() - && cell1.isDim() === cell2.isDim(); + && cell1.isDim() === cell2.isDim() + && cell1.isStrikethrough() === cell2.isStrikethrough(); } class StringSerializeHandler extends BaseSerializeHandler { @@ -160,7 +161,7 @@ class StringSerializeHandler extends BaseSerializeHandler { if ( // you must output character to cause overflow, control sequence can't do this nextRowFirstChar.getChars() && - isNextRowFirstCharDoubleWidth ? this._nullCellCount <= 1 : this._nullCellCount <= 0 + isNextRowFirstCharDoubleWidth ? this._nullCellCount <= 1 : this._nullCellCount <= 0 ) { if ( // the last character can't be null, @@ -259,6 +260,7 @@ class StringSerializeHandler extends BaseSerializeHandler { if (cell.isInvisible() !== oldCell.isInvisible()) { sgrSeq.push(cell.isInvisible() ? 8 : 28); } if (cell.isItalic() !== oldCell.isItalic()) { sgrSeq.push(cell.isItalic() ? 3 : 23); } if (cell.isDim() !== oldCell.isDim()) { sgrSeq.push(cell.isDim() ? 2 : 22); } + if (cell.isStrikethrough() !== oldCell.isStrikethrough()) { sgrSeq.push(cell.isStrikethrough() ? 9 : 29); } } } } diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 13a32126..84b715e8 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -84,7 +84,7 @@ declare module 'xterm-headless' { * line height and letter spacing is used. Note that this doesn't work with the DOM renderer * which renders all characters using the font. The default is true. */ - customGlyphs?: boolean; + customGlyphs?: boolean; /** * Whether input should be disabled. @@ -1085,18 +1085,20 @@ declare module 'xterm-headless' { /** Whether the cell has the bold attribute (CSI 1 m). */ isBold(): number; - /** Whether the cell has the inverse attribute (CSI 3 m). */ + /** Whether the cell has the italic attribute (CSI 3 m). */ isItalic(): number; - /** Whether the cell has the inverse attribute (CSI 2 m). */ + /** Whether the cell has the dim attribute (CSI 2 m). */ isDim(): number; /** Whether the cell has the underline attribute (CSI 4 m). */ isUnderline(): number; - /** Whether the cell has the inverse attribute (CSI 5 m). */ + /** Whether the cell has the blink attribute (CSI 5 m). */ isBlink(): number; /** Whether the cell has the inverse attribute (CSI 7 m). */ isInverse(): number; - /** Whether the cell has the inverse attribute (CSI 8 m). */ + /** Whether the cell has the invisible attribute (CSI 8 m). */ isInvisible(): number; + /** Whether the cell has the strikethrough attribute (CSI 9 m). */ + isStrikethrough(): number; /** Whether the cell is using the RGB foreground color mode. */ isFgRGB(): boolean; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index ba2be988..6cf34bf8 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1444,18 +1444,20 @@ declare module 'xterm' { /** Whether the cell has the bold attribute (CSI 1 m). */ isBold(): number; - /** Whether the cell has the inverse attribute (CSI 3 m). */ + /** Whether the cell has the italic attribute (CSI 3 m). */ isItalic(): number; - /** Whether the cell has the inverse attribute (CSI 2 m). */ + /** Whether the cell has the dim attribute (CSI 2 m). */ isDim(): number; /** Whether the cell has the underline attribute (CSI 4 m). */ isUnderline(): number; - /** Whether the cell has the inverse attribute (CSI 5 m). */ + /** Whether the cell has the blink attribute (CSI 5 m). */ isBlink(): number; /** Whether the cell has the inverse attribute (CSI 7 m). */ isInverse(): number; - /** Whether the cell has the inverse attribute (CSI 8 m). */ + /** Whether the cell has the invisible attribute (CSI 8 m). */ isInvisible(): number; + /** Whether the cell has the strikethrough attribute (CSI 9 m). */ + isStrikethrough(): number; /** Whether the cell is using the RGB foreground color mode. */ isFgRGB(): boolean; From 3fe32c07246937729719e576ae5453f30b21edf6 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 22 Sep 2021 09:38:37 +0000 Subject: [PATCH 08/35] Adjust test to include strikethrough test --- .../test/SerializeAddon.api.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts index bb66f37b..97525226 100644 --- a/addons/xterm-addon-serialize/test/SerializeAddon.api.ts +++ b/addons/xterm-addon-serialize/test/SerializeAddon.api.ts @@ -184,11 +184,13 @@ describe('SerializeAddon', () => { sgr(UNDERLINED) + line, sgr(BLINK) + line, sgr(INVISIBLE) + line, + sgr(STRIKETHROUGH) + line, sgr(NO_INVERSE) + line, sgr(NO_BOLD) + line, sgr(NO_UNDERLINED) + line, sgr(NO_BLINK) + line, - sgr(NO_INVISIBLE) + line + sgr(NO_INVISIBLE) + line, + sgr(NO_STRIKETHROUGH) + line ]; const rows = lines.length; await writeSync(page, lines.join('\\r\\n')); @@ -579,20 +581,20 @@ const BG_RGB_GREEN = '48;2;0;255;0'; const BG_RGB_YELLOW = '48;2;255;255;0'; const BG_RESET = '49'; -const INVERSE = '7'; const BOLD = '1'; +const DIM = '2'; +const ITALIC = '3'; const UNDERLINED = '4'; const BLINK = '5'; +const INVERSE = '7'; const INVISIBLE = '8'; +const STRIKETHROUGH = '9'; -const NO_INVERSE = '27'; const NO_BOLD = '22'; +const NO_DIM = '22'; +const NO_ITALIC = '23'; const NO_UNDERLINED = '24'; const NO_BLINK = '25'; +const NO_INVERSE = '27'; const NO_INVISIBLE = '28'; - -const ITALIC = '3'; -const DIM = '2'; - -const NO_ITALIC = '23'; -const NO_DIM = '22'; +const NO_STRIKETHROUGH = '29'; From 1d1fffdabc12c792e31e3913be2fca5f3ba77177 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 22 Sep 2021 10:08:48 +0000 Subject: [PATCH 09/35] Include src files in distribution --- .npmignore | 9 +++++++++ addons/xterm-addon-attach/.npmignore | 9 +++++++++ addons/xterm-addon-fit/.npmignore | 9 +++++++++ addons/xterm-addon-ligatures/.npmignore | 9 +++++++++ addons/xterm-addon-search/.npmignore | 9 +++++++++ addons/xterm-addon-serialize/.npmignore | 9 +++++++++ addons/xterm-addon-unicode11/.npmignore | 9 +++++++++ addons/xterm-addon-web-links/.npmignore | 9 +++++++++ addons/xterm-addon-webgl/.npmignore | 9 +++++++++ headless/.npmignore | 9 +++++++++ 10 files changed, 90 insertions(+) diff --git a/.npmignore b/.npmignore index 71cc5e81..7b2c6b59 100644 --- a/.npmignore +++ b/.npmignore @@ -19,6 +19,15 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-attach/.npmignore b/addons/xterm-addon-attach/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-attach/.npmignore +++ b/addons/xterm-addon-attach/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-fit/.npmignore b/addons/xterm-addon-fit/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-fit/.npmignore +++ b/addons/xterm-addon-fit/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-ligatures/.npmignore b/addons/xterm-addon-ligatures/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-ligatures/.npmignore +++ b/addons/xterm-addon-ligatures/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-search/.npmignore b/addons/xterm-addon-search/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-search/.npmignore +++ b/addons/xterm-addon-search/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-serialize/.npmignore b/addons/xterm-addon-serialize/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-serialize/.npmignore +++ b/addons/xterm-addon-serialize/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-unicode11/.npmignore b/addons/xterm-addon-unicode11/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-unicode11/.npmignore +++ b/addons/xterm-addon-unicode11/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-web-links/.npmignore b/addons/xterm-addon-web-links/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-web-links/.npmignore +++ b/addons/xterm-addon-web-links/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-webgl/.npmignore b/addons/xterm-addon-webgl/.npmignore index fc460879..00b53247 100644 --- a/addons/xterm-addon-webgl/.npmignore +++ b/addons/xterm-addon-webgl/.npmignore @@ -10,5 +10,14 @@ !lib/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts diff --git a/headless/.npmignore b/headless/.npmignore index 20a02782..3c9d7e8f 100644 --- a/headless/.npmignore +++ b/headless/.npmignore @@ -10,5 +10,14 @@ !lib-headless/**/*.css +# Whitelist - src/ +!src/**/*.ts +!src/**/*.d.ts + +!src/**/*.js +!src/**/*.js.map + +!src/**/*.css + # Whitelist - typings/ !typings/*.d.ts From 189ff562242baa8cb9dea7c510b9377da9cd39a2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 22 Sep 2021 06:38:47 -0700 Subject: [PATCH 10/35] Add API to clear canvas renderer texture atlas Fixes #3455 --- src/browser/Terminal.ts | 4 ++++ src/browser/TestUtils.test.ts | 6 ++++++ src/browser/Types.d.ts | 1 + src/browser/public/Terminal.ts | 3 +++ src/browser/renderer/BaseRenderLayer.ts | 4 ++++ src/browser/renderer/Renderer.ts | 6 ++++++ src/browser/renderer/Types.d.ts | 6 ++++++ src/browser/renderer/atlas/BaseCharAtlas.ts | 2 ++ src/browser/renderer/atlas/DynamicCharAtlas.ts | 10 ++++++++++ src/browser/services/RenderService.ts | 5 +++++ src/browser/services/Services.ts | 1 + typings/xterm.d.ts | 8 ++++++++ 12 files changed, 56 insertions(+) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index ebe755bc..4e6a2201 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -1290,6 +1290,10 @@ export class Terminal extends CoreTerminal implements ITerminal { this.viewport?.syncScrollArea(); } + public clearTextureAtlas(): void { + this._renderService?.clearTextureAtlas(); + } + private _reportWindowsOptions(type: WindowsOptionsReportType): void { if (!this._renderService) { return; diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index daa6843c..8fdf458e 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -195,6 +195,9 @@ export class MockTerminal implements ITerminal { public reset(): void { throw new Error('Method not implemented.'); } + public clearTextureAtlas(): void { + throw new Error('Method not implemented.'); + } public refresh(start: number, end: number): void { throw new Error('Method not implemented.'); } @@ -374,6 +377,9 @@ export class MockRenderService implements IRenderService { public refreshRows(start: number, end: number): void { throw new Error('Method not implemented.'); } + public clearTextureAtlas(): void { + throw new Error('Method not implemented.'); + } public resize(cols: number, rows: number): void { throw new Error('Method not implemented.'); } diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index 0d74b39f..bafeff77 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -79,6 +79,7 @@ export interface IPublicTerminal extends IDisposable { write(data: string | Uint8Array, callback?: () => void): void; paste(data: string): void; refresh(start: number, end: number): void; + clearTextureAtlas(): void; reset(): void; } diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index a76b1a22..26cf2728 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -222,6 +222,9 @@ export class Terminal implements ITerminalApi { public reset(): void { this._core.reset(); } + public clearTextureAtlas(): void { + this._core.clearTextureAtlas(); + } public loadAddon(addon: ITerminalAddon): void { return this._addonManager.loadAddon(this, addon); } diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 448451d0..68f83a75 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -138,6 +138,10 @@ export abstract class BaseRenderLayer implements IRenderLayer { public abstract reset(): void; + public clearTextureAtlas(): void { + this._charAtlas?.clear(); + } + /** * Fills 1+ cells completely. This uses the existing fillStyle on the context. * @param x The column to start at. diff --git a/src/browser/renderer/Renderer.ts b/src/browser/renderer/Renderer.ts index d5de40db..162a7ed3 100644 --- a/src/browser/renderer/Renderer.ts +++ b/src/browser/renderer/Renderer.ts @@ -149,6 +149,12 @@ export class Renderer extends Disposable implements IRenderer { } } + public clearTextureAtlas(): void { + for (const layer of this._renderLayers) { + layer.clearTextureAtlas(); + } + } + /** * Recalculates the character and canvas dimensions. */ diff --git a/src/browser/renderer/Types.d.ts b/src/browser/renderer/Types.d.ts index fc137bc8..6818a926 100644 --- a/src/browser/renderer/Types.d.ts +++ b/src/browser/renderer/Types.d.ts @@ -52,6 +52,7 @@ export interface IRenderer extends IDisposable { onOptionsChanged(): void; clear(): void; renderRows(start: number, end: number): void; + clearTextureAtlas?(): void; } export interface IRenderLayer extends IDisposable { @@ -100,4 +101,9 @@ export interface IRenderLayer extends IDisposable { * Clear the state of the render layer. */ reset(): void; + + /** + * Clears the texture atlas. + */ + clearTextureAtlas(): void; } diff --git a/src/browser/renderer/atlas/BaseCharAtlas.ts b/src/browser/renderer/atlas/BaseCharAtlas.ts index 4ebaaa47..83c30d2f 100644 --- a/src/browser/renderer/atlas/BaseCharAtlas.ts +++ b/src/browser/renderer/atlas/BaseCharAtlas.ts @@ -28,6 +28,8 @@ export abstract class BaseCharAtlas implements IDisposable { */ private _doWarmUp(): void { } + public clear(): void { } + /** * Called when we start drawing a new frame. * diff --git a/src/browser/renderer/atlas/DynamicCharAtlas.ts b/src/browser/renderer/atlas/DynamicCharAtlas.ts index a7237878..666324ad 100644 --- a/src/browser/renderer/atlas/DynamicCharAtlas.ts +++ b/src/browser/renderer/atlas/DynamicCharAtlas.ts @@ -119,6 +119,16 @@ export class DynamicCharAtlas extends BaseCharAtlas { this._drawToCacheCount = 0; } + public clear(): void { + if (this._cacheMap.size > 0) { + const capacity = this._width * this._height; + this._cacheMap = new LRUMap(capacity); + this._cacheMap.prealloc(capacity); + } + this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); + this._tmpCtx.clearRect(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight); + } + public draw( ctx: CanvasRenderingContext2D, glyph: IGlyphIdentifier, diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index 332e71da..b8283e0e 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -168,6 +168,11 @@ export class RenderService extends Disposable implements IRenderService { } } + public clearTextureAtlas(): void { + this._renderer?.clearTextureAtlas?.(); + this._fullRefresh(); + } + public setColors(colors: IColorSet): void { this._renderer.setColors(colors); this._fullRefresh(); diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 8c8a7bd9..4928fa28 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -53,6 +53,7 @@ export interface IRenderService extends IDisposable { dimensions: IRenderDimensions; refreshRows(start: number, end: number): void; + clearTextureAtlas(): void; resize(cols: number, rows: number): void; changeOptions(): void; setRenderer(renderer: IRenderer): void; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index ba2be988..66d45f32 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1056,6 +1056,14 @@ declare module 'xterm' { */ refresh(start: number, end: number): void; + /** + * Clears the texture atlas of the canvas renderer if it's active. Doing this will force a + * redraw of all glyphs which can workaround issues causing the texture to become corrupt, for + * example Chromium/Nvidia has an issue where the texture gets messed up when resuming the OS + * from sleep. + */ + clearTextureAtlas(): void; + /** * Perform a full reset (RIS, aka '\x1bc'). */ From 3a71b3f11e9781e0df834bafdf8c51a007b06920 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 22 Sep 2021 14:21:50 -0700 Subject: [PATCH 11/35] Add document role to accessibility tree root See microsoft/vscode#98918 --- src/browser/AccessibilityManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index 1be3342d..80092202 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -53,6 +53,7 @@ export class AccessibilityManager extends Disposable { ) { super(); this._accessibilityTreeRoot = document.createElement('div'); + this._accessibilityTreeRoot.setAttribute('role', 'document'); this._accessibilityTreeRoot.classList.add('xterm-accessibility'); this._rowContainer = document.createElement('div'); From 0d14336ec58d1ab80e5f93021e85c35d4fa5067c Mon Sep 17 00:00:00 2001 From: Johan Knutzen Date: Wed, 22 Sep 2021 17:39:21 -0700 Subject: [PATCH 12/35] Add FleetDeck to real-world uses --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4ef592c2..ce687da9 100644 --- a/README.md +++ b/README.md @@ -169,6 +169,7 @@ Xterm.js is used in several world-class applications to provide great terminal e - [**TeleType**](https://github.com/akshaykmr/TeleType): cli tool that allows you to share your terminal online conveniently. Show off mad cli-fu, help a colleague, teach, or troubleshoot. - [**Intervue**](https://www.intervue.io): Pair programming for interviews. Multiple programming languages supported, with results displayed by xterm.js. - [**TRASA**](https://trasa.io): Zero trust access to Web, SSH, RDP and Database services. +- [**FleetDeck**](https://fleetdeck.io): Remote desktop & virtual terminal [And much more...](https://github.com/xtermjs/xterm.js/network/dependents) 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. Note: Please add any new contributions to the end of the list only. From 014530f58216e58b1aeae6757357c3de01eff919 Mon Sep 17 00:00:00 2001 From: "mac.bae" Date: Thu, 7 Oct 2021 07:44:30 +0000 Subject: [PATCH 13/35] Added goormIDE on Real-world uses --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 720e703c..e6d8f9a9 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ Xterm.js is used in several world-class applications to provide great terminal e - [**HashiCorp Nomad**](https://www.nomadproject.io/): A container orchestrator with the ability to connect to remote tasks via a web interface using websockets and xterm.js. - [**TermPair**](https://github.com/cs01/termpair): View and control terminals from your browser with end-to-end encryption - [**gdbgui**](https://github.com/cs01/gdbgui): Browser-based frontend to gdb (gnu debugger) +- [**goormIDE**](https://ide.goorm.io/): Run almost every programming languages with real-time collaboration, live pair programming, and built-in messenger. - [And much more...](https://github.com/xtermjs/xterm.js/network/dependents) 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 on our list. Note: Please add any new contributions to the end of the list only. From 37a4100220ed19e003b39e4c3c23acbfe207fea1 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Fri, 8 Oct 2021 07:45:48 -0700 Subject: [PATCH 14/35] throw if activate webgl called on safari --- addons/xterm-addon-webgl/src/WebglAddon.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index ad2393d8..b8bcf5b1 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -8,6 +8,7 @@ import { WebglRenderer } from './WebglRenderer'; import { ICharacterJoinerService, IRenderService } from 'browser/services/Services'; import { IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; +import { isSafari } from 'common/Platform'; export class WebglAddon implements ITerminalAddon { private _terminal?: Terminal; @@ -23,6 +24,9 @@ export class WebglAddon implements ITerminalAddon { if (!terminal.element) { throw new Error('Cannot activate WebglAddon before Terminal.open'); } + if (isSafari) { + throw new Error('Webgl is not currently supported on Safari'); + } this._terminal = terminal; const renderService: IRenderService = (terminal as any)._core._renderService; const characterJoinerService: ICharacterJoinerService = (terminal as any)._core._characterJoinerService; From 0c604789530ff416ed88ccec61eee126c5843bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 10 Oct 2021 19:36:20 +0200 Subject: [PATCH 15/35] fix DECTCEM in DOM renderer --- .../dom/DomRendererRowFactory.test.ts | 56 ++++++++++--------- .../renderer/dom/DomRendererRowFactory.ts | 7 ++- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/browser/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts index 2f8d264a..f41e5d44 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -10,7 +10,7 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, FgFlags, import { BufferLine, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { IBufferLine } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; -import { MockOptionsService } from 'common/TestUtils.test'; +import { MockCoreService, MockOptionsService } from 'common/TestUtils.test'; import { css } from 'browser/Color'; import { MockCharacterJoinerService } from 'browser/TestUtils.test'; @@ -21,30 +21,36 @@ describe('DomRendererRowFactory', () => { beforeEach(() => { dom = new jsdom.JSDOM(''); - rowFactory = new DomRendererRowFactory(dom.window.document, { - background: css.toColor('#010101'), - foreground: css.toColor('#020202'), - ansi: [ - // dark: - css.toColor('#2e3436'), - css.toColor('#cc0000'), - css.toColor('#4e9a06'), - css.toColor('#c4a000'), - css.toColor('#3465a4'), - css.toColor('#75507b'), - css.toColor('#06989a'), - css.toColor('#d3d7cf'), - // bright: - css.toColor('#555753'), - css.toColor('#ef2929'), - css.toColor('#8ae234'), - css.toColor('#fce94f'), - css.toColor('#729fcf'), - css.toColor('#ad7fa8'), - css.toColor('#34e2e2'), - css.toColor('#eeeeec') - ] - } as any, new MockCharacterJoinerService(), new MockOptionsService({ drawBoldTextInBrightColors: true })); + rowFactory = new DomRendererRowFactory( + dom.window.document, + { + background: css.toColor('#010101'), + foreground: css.toColor('#020202'), + ansi: [ + // dark: + css.toColor('#2e3436'), + css.toColor('#cc0000'), + css.toColor('#4e9a06'), + css.toColor('#c4a000'), + css.toColor('#3465a4'), + css.toColor('#75507b'), + css.toColor('#06989a'), + css.toColor('#d3d7cf'), + // bright: + css.toColor('#555753'), + css.toColor('#ef2929'), + css.toColor('#8ae234'), + css.toColor('#fce94f'), + css.toColor('#729fcf'), + css.toColor('#ad7fa8'), + css.toColor('#34e2e2'), + css.toColor('#eeeeec') + ] + } as any, + new MockCharacterJoinerService(), + new MockOptionsService({ drawBoldTextInBrightColors: true }), + new MockCoreService() + ); lineData = createEmptyLineData(2); }); diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index a61ebd73..a24f3e46 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -7,7 +7,7 @@ import { IBufferLine } from 'common/Types'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants'; import { CellData } from 'common/buffer/CellData'; -import { IOptionsService } from 'common/services/Services'; +import { ICoreService, IOptionsService } from 'common/services/Services'; import { color, rgba } from 'browser/Color'; import { IColorSet, IColor } from 'browser/Types'; import { ICharacterJoinerService } from 'browser/services/Services'; @@ -31,7 +31,8 @@ export class DomRendererRowFactory { private readonly _document: Document, private _colors: IColorSet, @ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService, - @IOptionsService private readonly _optionsService: IOptionsService + @IOptionsService private readonly _optionsService: IOptionsService, + @ICoreService private readonly _coreService: ICoreService ) { } @@ -110,7 +111,7 @@ export class DomRendererRowFactory { } } - if (isCursorRow && x === cursorX) { + if (!this._coreService.isCursorHidden && isCursorRow && x === cursorX) { charElement.classList.add(CURSOR_CLASS); if (cursorBlink) { From 5d5f34f65f8ffd9469d6ced1738ebc7d27d68485 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 12 Oct 2021 09:05:44 -0700 Subject: [PATCH 16/35] Report focus state on DECSET 1004 Fixes #2333 --- src/browser/Terminal.ts | 9 +++++++++ src/common/InputHandler.ts | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index dde4a1b6..513fdf62 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -150,6 +150,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // Setup InputHandler listeners this.register(this._inputHandler.onRequestBell(() => this.bell())); this.register(this._inputHandler.onRequestRefreshRows((start, end) => this.refresh(start, end))); + this.register(this._inputHandler.onRequestSendFocus(() => this._reportFocus())); this.register(this._inputHandler.onRequestReset(() => this.reset())); this.register(this._inputHandler.onRequestWindowsOptionsReport(type => this._reportWindowsOptions(type))); this.register(this._inputHandler.onAnsiColorChange((event) => this._changeAnsiColor(event))); @@ -1238,6 +1239,14 @@ export class Terminal extends CoreTerminal implements ITerminal { this.viewport?.syncScrollArea(); } + private _reportFocus(): void { + if (this.element?.classList.contains('focus')) { + this.coreService.triggerDataEvent(C0.ESC + '[I'); + } else { + this.coreService.triggerDataEvent(C0.ESC + '[O'); + } + } + private _reportWindowsOptions(type: WindowsOptionsReportType): void { if (!this._renderService) { return; diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index d4354e90..0f91a011 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -240,6 +240,8 @@ export class InputHandler extends Disposable implements IInputHandler { public get onRequestRefreshRows(): IEvent { return this._onRequestRefreshRows.event; } private _onRequestReset = new EventEmitter(); public get onRequestReset(): IEvent { return this._onRequestReset.event; } + private _onRequestSendFocus = new EventEmitter(); + public get onRequestSendFocus(): IEvent { return this._onRequestSendFocus.event; } private _onRequestSyncScrollBar = new EventEmitter(); public get onRequestSyncScrollBar(): IEvent { return this._onRequestSyncScrollBar.event; } private _onRequestWindowsOptionsReport = new EventEmitter(); @@ -1976,6 +1978,7 @@ export class InputHandler extends Disposable implements IInputHandler { // focusin: ^[[I // focusout: ^[[O this._coreService.decPrivateModes.sendFocus = true; + this._onRequestSendFocus.fire(); break; case 1005: // utf8 ext mode mouse - removed in #2507 this._logService.debug('DECSET 1005 not supported (see #2507)'); From 581272ee51129ee2431718b03e90755aed63d8ba Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 19 Oct 2021 10:28:09 -0700 Subject: [PATCH 17/35] Swallow error when opener can't be sent Fixes #2943 Co-authored-by: Megan Rogge --- addons/xterm-addon-web-links/src/WebLinksAddon.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addons/xterm-addon-web-links/src/WebLinksAddon.ts b/addons/xterm-addon-web-links/src/WebLinksAddon.ts index 46ddcf7b..dd1c1f17 100644 --- a/addons/xterm-addon-web-links/src/WebLinksAddon.ts +++ b/addons/xterm-addon-web-links/src/WebLinksAddon.ts @@ -29,7 +29,11 @@ const strictUrlRegex = new RegExp(start + protocolClause + bodyClause + end); function handleLink(event: MouseEvent, uri: string): void { const newWindow = window.open(); if (newWindow) { - newWindow.opener = null; + try { + newWindow.opener = null; + } catch { + // no-op, Electron can throw + } newWindow.location.href = uri; } else { console.warn('Opening link blocked as opener could not be cleared'); From 472e410205fb622f617ad8d70fa2c35e5106bb95 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 19 Oct 2021 10:49:01 -0700 Subject: [PATCH 18/35] Call out deserialize into same size terminal Fixes #3093 Co-authored-by: Megan Rogge --- .../xterm-addon-serialize/typings/xterm-addon-serialize.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts b/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts index b55ee303..23290af4 100644 --- a/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts +++ b/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts @@ -24,6 +24,10 @@ declare module 'xterm-addon-serialize' { * the state. The cursor will also be positioned to the correct cell. When restoring a terminal * it is best to do before `Terminal.open` is called to avoid wasting CPU cycles rendering * incomplete frames. + * + * It's recommended that you write the serialized data into a terminal of the same size in which + * it originated from and then resize it after if needed. + * * @param scrollback The number of rows in scrollback buffer to serialize, starting from the * bottom of the scrollback buffer. This defaults to the all available rows in the scrollback * buffer. From f46ed82d7ebe33e4ec665877389683616c619a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Thu, 21 Oct 2021 12:35:03 +0200 Subject: [PATCH 19/35] simplify wheel handlers --- src/browser/Terminal.ts | 45 +++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 4afca04c..2cd9bf99 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -699,8 +699,7 @@ export class Terminal extends CoreTerminal implements ITerminal { }, wheel: (ev: WheelEvent) => { sendEvent(ev); - ev.preventDefault(); - return this.cancel(ev); + return this.cancel(ev, true); }, mousedrag: (ev: MouseEvent) => { // deal only with move while a button is held @@ -795,33 +794,31 @@ export class Terminal extends CoreTerminal implements ITerminal { })); this.register(addDisposableDomListener(el, 'wheel', (ev: WheelEvent) => { - if (!requestedEvents.wheel) { + // do nothing, if app side handles wheel itself + if (requestedEvents.wheel) return; + + if (!this.buffer.hasScrollback) { // Convert wheel events into up/down events when the buffer does not have scrollback, this // enables scrolling in apps hosted in the alt buffer such as vim or tmux. - if (!this.buffer.hasScrollback) { - const amount = this.viewport!.getLinesScrolled(ev); + const amount = this.viewport!.getLinesScrolled(ev); - // Do nothing if there's no vertical scroll - if (amount === 0) { - return; - } - - // Construct and send sequences - const sequence = C0.ESC + (this.coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B'); - let data = ''; - for (let i = 0; i < Math.abs(amount); i++) { - data += sequence; - } - this.coreService.triggerDataEvent(data, true); + // Do nothing if there's no vertical scroll + if (amount === 0) { + return; } - return; - } - }, { passive: true })); - // allow wheel scrolling in - // the shell for example - this.register(addDisposableDomListener(el, 'wheel', (ev: WheelEvent) => { - if (requestedEvents.wheel) return; + // Construct and send sequences + const sequence = C0.ESC + (this.coreService.decPrivateModes.applicationCursorKeys ? 'O' : '[') + (ev.deltaY < 0 ? 'A' : 'B'); + let data = ''; + for (let i = 0; i < Math.abs(amount); i++) { + data += sequence; + } + this.coreService.triggerDataEvent(data, true); + return this.cancel(ev, true); + } + + // normal viewport scrolling + // conditionally stop event, if the viewport still had rows to scroll within if (!this.viewport!.onWheel(ev)) { return this.cancel(ev); } From d2bcbc73d3e24b5f0d063e14d3e6fb9b15416e61 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 21 Oct 2021 10:33:22 -0700 Subject: [PATCH 20/35] fixes #3517 Co-authored-by: Daniel Imms --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 2 +- .../src/renderLayer/CursorRenderLayer.ts | 25 +++++++------------ src/browser/renderer/CursorRenderLayer.ts | 24 ++++++------------ 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 9b75d1de..8c59cd8a 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -60,7 +60,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._renderLayers = [ new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core), - new CursorRenderLayer(this._core.screenElement!, 3, this._colors, this._onRequestRedraw) + new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._onRequestRedraw) ]; this.dimensions = { scaledCharWidth: 0, diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index b2e834d3..8bad1be9 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -31,6 +31,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _cell: ICellData = new CellData(); constructor( + terminal: Terminal, container: HTMLElement, zIndex: number, colors: IColorSet, @@ -49,7 +50,7 @@ export class CursorRenderLayer extends BaseRenderLayer { 'block': this._renderBlockCursor.bind(this), 'underline': this._renderUnderlineCursor.bind(this) }; - // TODO: Consider initial options? Maybe onOptionsChanged should be called at the end of open? + this.onOptionsChanged(terminal); } public resize(terminal: Terminal, dim: IRenderDimensions): void { @@ -66,25 +67,18 @@ export class CursorRenderLayer extends BaseRenderLayer { public reset(terminal: Terminal): void { this._clearCursor(); - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.dispose(); - this.onOptionsChanged(terminal); - } + this._cursorBlinkStateManager?.restartBlinkAnimation(terminal); + this.onOptionsChanged(terminal); } public onBlur(terminal: Terminal): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.pause(); - } + this._cursorBlinkStateManager?.pause(); this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.active.cursorY, end: terminal.buffer.active.cursorY }); } public onFocus(terminal: Terminal): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.resume(terminal); - } else { - this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.active.cursorY, end: terminal.buffer.active.cursorY }); - } + this._cursorBlinkStateManager?.resume(terminal); + this._onRequestRefreshRowsEvent.fire({ start: terminal.buffer.active.cursorY, end: terminal.buffer.active.cursorY }); } public onOptionsChanged(terminal: Terminal): void { @@ -104,9 +98,7 @@ export class CursorRenderLayer extends BaseRenderLayer { } public onCursorMove(terminal: Terminal): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.restartBlinkAnimation(terminal); - } + this._cursorBlinkStateManager?.restartBlinkAnimation(terminal); } public onGridChanged(terminal: Terminal, startRow: number, endRow: number): void { @@ -296,6 +288,7 @@ class CursorBlinkStateManager { // Clear any existing interval if (this._blinkInterval) { window.clearInterval(this._blinkInterval); + this._blinkInterval = undefined; } // Setup the initial timeout which will hide the cursor, this is done before diff --git a/src/browser/renderer/CursorRenderLayer.ts b/src/browser/renderer/CursorRenderLayer.ts index a78b2048..b30a09dd 100644 --- a/src/browser/renderer/CursorRenderLayer.ts +++ b/src/browser/renderer/CursorRenderLayer.ts @@ -55,7 +55,6 @@ export class CursorRenderLayer extends BaseRenderLayer { 'block': this._renderBlockCursor.bind(this), 'underline': this._renderUnderlineCursor.bind(this) }; - // TODO: Consider initial options? Maybe onOptionsChanged should be called at the end of open? } public resize(dim: IRenderDimensions): void { @@ -72,26 +71,18 @@ export class CursorRenderLayer extends BaseRenderLayer { public reset(): void { this._clearCursor(); - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.dispose(); - this._cursorBlinkStateManager = undefined; - this.onOptionsChanged(); - } + this._cursorBlinkStateManager?.restartBlinkAnimation(); + this.onOptionsChanged(); } public onBlur(): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.pause(); - } + this._cursorBlinkStateManager?.pause(); this._onRequestRedraw.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); } public onFocus(): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.resume(); - } else { - this._onRequestRedraw.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); - } + this._cursorBlinkStateManager?.resume(); + this._onRequestRedraw.fire({ start: this._bufferService.buffer.y, end: this._bufferService.buffer.y }); } public onOptionsChanged(): void { @@ -111,9 +102,7 @@ export class CursorRenderLayer extends BaseRenderLayer { } public onCursorMove(): void { - if (this._cursorBlinkStateManager) { - this._cursorBlinkStateManager.restartBlinkAnimation(); - } + this._cursorBlinkStateManager?.restartBlinkAnimation(); } public onGridChanged(startRow: number, endRow: number): void { @@ -300,6 +289,7 @@ class CursorBlinkStateManager { // Clear any existing interval if (this._blinkInterval) { window.clearInterval(this._blinkInterval); + this._blinkInterval = undefined; } // Setup the initial timeout which will hide the cursor, this is done before From d6e828a2f3ec5ba3110fe2ca3e714bde8b5e34e5 Mon Sep 17 00:00:00 2001 From: Megan Rogge Date: Thu, 21 Oct 2021 10:44:21 -0700 Subject: [PATCH 21/35] fix merge conflict --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 4b80cc6c..af1591a8 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -60,7 +60,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._renderLayers = [ new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core), - new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._onRequestRedraw) + new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._core, this._onRequestRedraw) ]; this.dimensions = { scaledCharWidth: 0, From b8766394292883ee3962c9ba5e43201c2987cd8e Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 21 Oct 2021 11:43:20 -0700 Subject: [PATCH 22/35] Use Ubuntu 18.04 in release job Fixes #3521 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5d4e9918..b66c301e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -147,7 +147,7 @@ jobs: - Windows_IntegrationTests condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['FORCE_RELEASE'], 'true'))) pool: - vmImage: 'ubuntu-16.04' + vmImage: 'ubuntu-18.04' steps: - task: NodeTool@0 inputs: From 780b48db5387de3a292faba7f8bd24b1a922abb7 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 21 Oct 2021 12:54:01 -0700 Subject: [PATCH 23/35] Move newest to bottom of list --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 137d2c0f..93675f32 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,6 @@ Xterm.js is used in several world-class applications to provide great terminal e - [**TeleType**](https://github.com/akshaykmr/TeleType): cli tool that allows you to share your terminal online conveniently. Show off mad cli-fu, help a colleague, teach, or troubleshoot. - [**Intervue**](https://www.intervue.io): Pair programming for interviews. Multiple programming languages are supported, with results displayed by xterm.js. - [**TRASA**](https://trasa.io): Zero trust access to Web, SSH, RDP, and Database services. -- [**FleetDeck**](https://fleetdeck.io): Remote desktop & virtual terminal - [**Commas**](https://github.com/CyanSalt/commas): Commas is a hackable terminal and command runner. - [**Devtron**](https://github.com/devtron-labs/devtron): Software Delivery Workflow For Kubernetes. - [**NxShell**](https://github.com/nxshell/nxshell): An easy to use new terminal for SSH. @@ -185,6 +184,7 @@ Xterm.js is used in several world-class applications to provide great terminal e - [**TermPair**](https://github.com/cs01/termpair): View and control terminals from your browser with end-to-end encryption - [**gdbgui**](https://github.com/cs01/gdbgui): Browser-based frontend to gdb (gnu debugger) - [**goormIDE**](https://ide.goorm.io/): Run almost every programming languages with real-time collaboration, live pair programming, and built-in messenger. +- [**FleetDeck**](https://fleetdeck.io): Remote desktop & virtual terminal - [And much more...](https://github.com/xtermjs/xterm.js/network/dependents) 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 on our list. Note: Please add any new contributions to the end of the list only. From c9e8db38b6763d2c552bf0e1487fdbcb2889e2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Fri, 22 Oct 2021 13:32:31 +0200 Subject: [PATCH 24/35] properly await all parseP calls --- src/common/InputHandler.test.ts | 82 ++++++++++++++++----------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index 92162d9a..e25c3df1 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -77,54 +77,54 @@ describe('InputHandler', () => { optionsService.options.scrollback = 1; bufferService.reset(); }); - it('SL (scrollLeft)', () => { - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[ @'); + it('SL (scrollLeft)', async () => { + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[ @'); assert.deepEqual(getLines(bufferService, 6), ['12345', '2345', '2345', '2345', '2345', '2345']); - inputHandler.parseP('\x1b[0 @'); + await inputHandler.parseP('\x1b[0 @'); assert.deepEqual(getLines(bufferService, 6), ['12345', '345', '345', '345', '345', '345']); - inputHandler.parseP('\x1b[2 @'); + await inputHandler.parseP('\x1b[2 @'); assert.deepEqual(getLines(bufferService, 6), ['12345', '5', '5', '5', '5', '5']); }); - it('SR (scrollRight)', () => { - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[ A'); + it('SR (scrollRight)', async () => { + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[ A'); assert.deepEqual(getLines(bufferService, 6), ['12345', ' 1234', ' 1234', ' 1234', ' 1234', ' 1234']); - inputHandler.parseP('\x1b[0 A'); + await inputHandler.parseP('\x1b[0 A'); assert.deepEqual(getLines(bufferService, 6), ['12345', ' 123', ' 123', ' 123', ' 123', ' 123']); - inputHandler.parseP('\x1b[2 A'); + await inputHandler.parseP('\x1b[2 A'); assert.deepEqual(getLines(bufferService, 6), ['12345', ' 1', ' 1', ' 1', ' 1', ' 1']); }); - it('insertColumns (DECIC)', () => { - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[3;3H'); - inputHandler.parseP('\x1b[\'}'); + it('insertColumns (DECIC)', async () => { + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[3;3H'); + await inputHandler.parseP('\x1b[\'}'); assert.deepEqual(getLines(bufferService, 6), ['12345', '12 34', '12 34', '12 34', '12 34', '12 34']); bufferService.reset(); - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[3;3H'); - inputHandler.parseP('\x1b[1\'}'); + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[3;3H'); + await inputHandler.parseP('\x1b[1\'}'); assert.deepEqual(getLines(bufferService, 6), ['12345', '12 34', '12 34', '12 34', '12 34', '12 34']); bufferService.reset(); - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[3;3H'); - inputHandler.parseP('\x1b[2\'}'); + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[3;3H'); + await inputHandler.parseP('\x1b[2\'}'); assert.deepEqual(getLines(bufferService, 6), ['12345', '12 3', '12 3', '12 3', '12 3', '12 3']); }); - it('deleteColumns (DECDC)', () => { - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[3;3H'); - inputHandler.parseP('\x1b[\'~'); + it('deleteColumns (DECDC)', async () => { + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[3;3H'); + await inputHandler.parseP('\x1b[\'~'); assert.deepEqual(getLines(bufferService, 6), ['12345', '1245', '1245', '1245', '1245', '1245']); bufferService.reset(); - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[3;3H'); - inputHandler.parseP('\x1b[1\'~'); + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[3;3H'); + await inputHandler.parseP('\x1b[1\'~'); assert.deepEqual(getLines(bufferService, 6), ['12345', '1245', '1245', '1245', '1245', '1245']); bufferService.reset(); - inputHandler.parseP('12345'.repeat(6)); - inputHandler.parseP('\x1b[3;3H'); - inputHandler.parseP('\x1b[2\'~'); + await inputHandler.parseP('12345'.repeat(6)); + await inputHandler.parseP('\x1b[3;3H'); + await inputHandler.parseP('\x1b[2\'~'); assert.deepEqual(getLines(bufferService, 6), ['12345', '125', '125', '125', '125', '125']); }); }); @@ -137,41 +137,41 @@ describe('InputHandler', () => { bufferService.reset(); }); describe('reverseWraparound set', () => { - it('should not reverse outside of scroll margins', () => { + it('should not reverse outside of scroll margins', async () => { // prepare buffer content - inputHandler.parseP('#####abcdefghijklmnopqrstuvwxy'); + await inputHandler.parseP('#####abcdefghijklmnopqrstuvwxy'); assert.deepEqual(getLines(bufferService, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', 'uvwxy']); assert.equal(bufferService.buffers.active.ydisp, 1); assert.equal(bufferService.buffers.active.x, 5); assert.equal(bufferService.buffers.active.y, 4); - inputHandler.parseP(ttyBS.repeat(100)); + await inputHandler.parseP(ttyBS.repeat(100)); assert.deepEqual(getLines(bufferService, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', ' y']); - inputHandler.parseP('\x1b[?45h'); - inputHandler.parseP('uvwxy'); + await inputHandler.parseP('\x1b[?45h'); + await inputHandler.parseP('uvwxy'); // set top/bottom to 1/3 (0-based) - inputHandler.parseP('\x1b[2;4r'); + await inputHandler.parseP('\x1b[2;4r'); // place cursor below scroll bottom bufferService.buffers.active.x = 5; bufferService.buffers.active.y = 4; - inputHandler.parseP(ttyBS.repeat(100)); + await inputHandler.parseP(ttyBS.repeat(100)); assert.deepEqual(getLines(bufferService, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', ' ']); - inputHandler.parseP('uvwxy'); + await inputHandler.parseP('uvwxy'); // place cursor within scroll margins bufferService.buffers.active.x = 5; bufferService.buffers.active.y = 3; - inputHandler.parseP(ttyBS.repeat(100)); + await inputHandler.parseP(ttyBS.repeat(100)); assert.deepEqual(getLines(bufferService, 6), ['#####', 'abcde', ' ', ' ', ' ', 'uvwxy']); assert.equal(bufferService.buffers.active.x, 0); assert.equal(bufferService.buffers.active.y, bufferService.buffers.active.scrollTop); // stops at 0, scrollTop - inputHandler.parseP('fghijklmnopqrst'); + await inputHandler.parseP('fghijklmnopqrst'); // place cursor above scroll top bufferService.buffers.active.x = 5; bufferService.buffers.active.y = 0; - inputHandler.parseP(ttyBS.repeat(100)); + await inputHandler.parseP(ttyBS.repeat(100)); assert.deepEqual(getLines(bufferService, 6), ['#####', ' ', 'fghij', 'klmno', 'pqrst', 'uvwxy']); }); }); From 9b1eec8adea79bf48717c0dc3478707187ab0018 Mon Sep 17 00:00:00 2001 From: metonym Date: Fri, 22 Oct 2021 09:49:01 -0700 Subject: [PATCH 25/35] fix(viewport): account for fallback scrollbar width --- src/browser/Viewport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 3c9bea4c..afed55fa 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -116,7 +116,7 @@ export class Viewport extends Disposable implements IViewport { } this._lastHadScrollBar = this.scrollBarWidth > 0; - this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth).toString() + 'px'; + this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth + (this._lastHadScrollBar ? FALLBACK_SCROLL_BAR_WIDTH : 0)).toString() + 'px'; this._refreshAnimationFrame = null; } From 6c8d8018947b78e7bf4befe4ecadd9388ed9c9f3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 22 Oct 2021 10:14:03 -0700 Subject: [PATCH 26/35] Adopt typed options in demo client --- demo/client.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index a5ac8bb5..cd0657a0 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -293,11 +293,11 @@ function initOptions(term: TerminalType): void { rendererType: ['dom', 'canvas'], wordSeparator: null }; - const options = Object.keys((term)._core.options); + const options = Object.keys(term.options); const booleanOptions = []; const numberOptions = []; options.filter(o => blacklistedOptions.indexOf(o) === -1).forEach(o => { - switch (typeof term.getOption(o)) { + switch (typeof term.options[o]) { case 'boolean': booleanOptions.push(o); break; @@ -314,18 +314,18 @@ function initOptions(term: TerminalType): void { let html = ''; html += '
'; booleanOptions.forEach(o => { - html += `
`; + html += `
`; }); html += '
'; numberOptions.forEach(o => { - html += `
`; + html += `
`; }); html += '
'; Object.keys(stringOptions).forEach(o => { if (stringOptions[o]) { - html += `
`; + html += `
`; } else { - html += `
`; + html += `
`; } }); html += '
'; @@ -338,7 +338,7 @@ function initOptions(term: TerminalType): void { const input = document.getElementById(`opt-${o}`); addDomListener(input, 'change', () => { console.log('change', o, input.checked); - term.setOption(o, input.checked); + term.options[o] = input.checked; }); }); numberOptions.forEach(o => { @@ -347,14 +347,17 @@ function initOptions(term: TerminalType): void { console.log('change', o, input.value); if (o === 'cols' || o === 'rows') { updateTerminalSize(); - } else if (o === 'lineHeight' || o === 'scrollSensitivity') { - term.setOption(o, parseFloat(input.value)); + } else if (o === 'lineHeight') { + term.options.lineHeight = parseFloat(input.value); + updateTerminalSize(); + } else if (o === 'scrollSensitivity') { + term.options.scrollSensitivity = parseFloat(input.value); updateTerminalSize(); } else if(o === 'scrollback') { - term.setOption(o, parseInt(input.value)); + term.options.scrollback = parseInt(input.value); setTimeout(() => updateTerminalSize(), 5); } else { - term.setOption(o, parseInt(input.value)); + term.options[o] = parseInt(input.value); } }); }); @@ -362,7 +365,7 @@ function initOptions(term: TerminalType): void { const input = document.getElementById(`opt-${o}`); addDomListener(input, 'change', () => { console.log('change', o, input.value); - term.setOption(o, input.value); + term.options[o] = input.value; }); }); } From 4b9ab8184845a3ec727f51a6e2e54d99e1063a6c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 22 Oct 2021 10:34:25 -0700 Subject: [PATCH 27/35] Add deprecated to getOption/setOption --- typings/xterm.d.ts | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 3b59e4a9..f67e3a16 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -969,26 +969,31 @@ declare module 'xterm' { /** * Retrieves an option's value from the terminal. * @param key The option key. + * @deprecated Use `options` instead. */ getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; /** * Retrieves an option's value from the terminal. * @param key The option key. + * @deprecated Use `options` instead. */ getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell' | 'windowsMode'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. + * @deprecated Use `options` instead. */ getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number; /** * Retrieves an option's value from the terminal. * @param key The option key. + * @deprecated Use `options` instead. */ getOption(key: 'fontWeight' | 'fontWeightBold'): FontWeight; /** * Retrieves an option's value from the terminal. * @param key The option key. + * @deprecated Use `options` instead. */ getOption(key: string): any; @@ -996,60 +1001,70 @@ declare module 'xterm' { * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'fontFamily' | 'termName' | 'bellSound' | 'wordSeparator', value: string): void; /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + * @deprecated Use `options` instead. + */ setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number): void; /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + * @deprecated Use `options` instead. + */ setOption(key: 'logLevel', value: LogLevel): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'bellStyle', value: null | 'none' | 'visual' | 'sound' | 'both'): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'cursorStyle', value: null | 'block' | 'underline' | 'bar'): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'visualBell' | 'windowsMode', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'fontSize' | 'letterSpacing' | 'lineHeight' | 'tabStopWidth' | 'scrollback', value: number): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'theme', value: ITheme): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: 'cols' | 'rows', value: number): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. + * @deprecated Use `options` instead. */ setOption(key: string, value: any): void; From 7deb01267b384892b8d618f2527b51c5db6fc636 Mon Sep 17 00:00:00 2001 From: metonym Date: Fri, 22 Oct 2021 11:02:59 -0700 Subject: [PATCH 28/35] Use computed padding of terminal element to compute viewport width --- src/browser/Terminal.ts | 3 ++- src/browser/Viewport.ts | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 2cd9bf99..0047ce9f 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -494,7 +494,8 @@ export class Terminal extends CoreTerminal implements ITerminal { this.viewport = this._instantiationService.createInstance(Viewport, (amount: number) => this.scrollLines(amount, true, ScrollSource.VIEWPORT), this._viewportElement, - this._viewportScrollArea + this._viewportScrollArea, + this.element ); this.viewport.onThemeChange(this._colorManager.colors); this.register(this._inputHandler.onRequestSyncScrollBar(() => this.viewport!.syncScrollArea())); diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index afed55fa..f2cc6376 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -42,6 +42,7 @@ export class Viewport extends Disposable implements IViewport { private readonly _scrollLines: (amount: number) => void, private readonly _viewportElement: HTMLElement, private readonly _scrollArea: HTMLElement, + private readonly _element: HTMLElement, @IBufferService private readonly _bufferService: IBufferService, @IOptionsService private readonly _optionsService: IOptionsService, @ICharSizeService private readonly _charSizeService: ICharSizeService, @@ -115,8 +116,10 @@ export class Viewport extends Disposable implements IViewport { this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH; } this._lastHadScrollBar = this.scrollBarWidth > 0; - - this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth + (this._lastHadScrollBar ? FALLBACK_SCROLL_BAR_WIDTH : 0)).toString() + 'px'; + + const elementStyle = window.getComputedStyle(this._element); + const elementPadding = parseInt(elementStyle.paddingLeft) + parseInt(elementStyle.paddingRight); + this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth + (this._lastHadScrollBar ? elementPadding : 0)).toString() + 'px'; this._refreshAnimationFrame = null; } From ed1aecb251797368593cce3c3cf7141512a2adb5 Mon Sep 17 00:00:00 2001 From: metonym Date: Fri, 22 Oct 2021 11:28:30 -0700 Subject: [PATCH 29/35] chore(viewport): run yarn lint --fix --- src/browser/Viewport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index f2cc6376..f73594bf 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -116,7 +116,7 @@ export class Viewport extends Disposable implements IViewport { this.scrollBarWidth = (this._viewportElement.offsetWidth - this._scrollArea.offsetWidth) || FALLBACK_SCROLL_BAR_WIDTH; } this._lastHadScrollBar = this.scrollBarWidth > 0; - + const elementStyle = window.getComputedStyle(this._element); const elementPadding = parseInt(elementStyle.paddingLeft) + parseInt(elementStyle.paddingRight); this._viewportElement.style.width = (this._renderService.dimensions.actualCellWidth * (this._bufferService.cols) + this.scrollBarWidth + (this._lastHadScrollBar ? elementPadding : 0)).toString() + 'px'; From 59f940c19c53fa440b7f8e21d027cb59fd821e86 Mon Sep 17 00:00:00 2001 From: Daniel Steinberg Date: Wed, 16 Jun 2021 23:16:36 +0000 Subject: [PATCH 30/35] Set text baseline conditionally by browser. --- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 4 ++-- addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts | 3 ++- src/browser/renderer/BaseRenderLayer.ts | 6 +++--- src/browser/renderer/atlas/Constants.ts | 6 ++++++ src/browser/renderer/atlas/DynamicCharAtlas.ts | 4 ++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 6128c836..609df6eb 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -4,7 +4,7 @@ */ import { ICharAtlasConfig } from './Types'; -import { DIM_OPACITY } from 'browser/renderer/atlas/Constants'; +import { DIM_OPACITY, TEXT_BASELINE } from 'browser/renderer/atlas/Constants'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; import { DEFAULT_COLOR, Attributes } from 'common/buffer/Constants'; import { throwIfFalsy } from '../WebglUtils'; @@ -368,7 +368,7 @@ export class WebglCharAtlas implements IDisposable { const fontStyle = italic ? 'italic' : ''; this._tmpCtx.font = `${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`; - this._tmpCtx.textBaseline = 'ideographic'; + this._tmpCtx.textBaseline = TEXT_BASELINE; this._tmpCtx.fillStyle = this._getForegroundCss(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, bold); diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index 532836ee..4c17aad4 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -7,6 +7,7 @@ import { IRenderLayer } from './Types'; import { acquireCharAtlas } from '../atlas/CharAtlasCache'; import { Terminal } from 'xterm'; import { IColorSet } from 'browser/Types'; +import { TEXT_BASELINE } from 'browser/renderer/atlas/Constants'; import { IRenderDimensions } from 'browser/renderer/Types'; import { CellData } from 'common/buffer/CellData'; import { WebglCharAtlas } from 'atlas/WebglCharAtlas'; @@ -224,7 +225,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { */ protected _fillCharTrueColor(terminal: Terminal, cell: CellData, x: number, y: number): void { this._ctx.font = this._getFont(terminal, false, false); - this._ctx.textBaseline = 'ideographic'; + this._ctx.textBaseline = TEXT_BASELINE; this._clipRow(terminal, y); this._ctx.fillText( cell.getChars(), diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index 68f83a75..40b6e3f9 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -7,7 +7,7 @@ import { IRenderDimensions, IRenderLayer } from 'browser/renderer/Types'; import { ICellData } from 'common/Types'; import { DEFAULT_COLOR, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants'; import { IGlyphIdentifier } from 'browser/renderer/atlas/Types'; -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; +import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/atlas/Constants'; import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas'; import { acquireCharAtlas } from 'browser/renderer/atlas/CharAtlasCache'; import { AttributeData } from 'common/buffer/AttributeData'; @@ -262,7 +262,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { */ protected _fillCharTrueColor(cell: CellData, x: number, y: number): void { this._ctx.font = this._getFont(false, false); - this._ctx.textBaseline = 'ideographic'; + this._ctx.textBaseline = TEXT_BASELINE; this._clipRow(y); // Draw custom characters if applicable @@ -350,7 +350,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { private _drawUncachedChars(cell: ICellData, x: number, y: number, fgOverride?: IColor): void { this._ctx.save(); this._ctx.font = this._getFont(!!cell.isBold(), !!cell.isItalic()); - this._ctx.textBaseline = 'ideographic'; + this._ctx.textBaseline = TEXT_BASELINE; if (cell.isInverse()) { if (fgOverride) { diff --git a/src/browser/renderer/atlas/Constants.ts b/src/browser/renderer/atlas/Constants.ts index 150aad88..e698bcd8 100644 --- a/src/browser/renderer/atlas/Constants.ts +++ b/src/browser/renderer/atlas/Constants.ts @@ -3,7 +3,13 @@ * @license MIT */ +import { isFirefox } from 'common/Platform'; + export const INVERTED_DEFAULT_COLOR = 257; export const DIM_OPACITY = 0.5; +// The text baseline is set conditionally by browser. Using 'ideographic' for Firefox would +// result in truncated text (Issue 3353). Using 'bottom' for Chrome would result in slightly +// unaligned Powerline fonts (PR 3356#issuecomment-850928179). +export const TEXT_BASELINE: CanvasTextBaseline = isFirefox ? 'bottom' : 'ideographic'; export const CHAR_ATLAS_CELL_SPACING = 1; diff --git a/src/browser/renderer/atlas/DynamicCharAtlas.ts b/src/browser/renderer/atlas/DynamicCharAtlas.ts index 666324ad..118dbcd2 100644 --- a/src/browser/renderer/atlas/DynamicCharAtlas.ts +++ b/src/browser/renderer/atlas/DynamicCharAtlas.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; +import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, TEXT_BASELINE } from 'browser/renderer/atlas/Constants'; import { IGlyphIdentifier, ICharAtlasConfig } from 'browser/renderer/atlas/Types'; import { BaseCharAtlas } from 'browser/renderer/atlas/BaseCharAtlas'; import { DEFAULT_ANSI_COLORS } from 'browser/ColorManager'; @@ -266,7 +266,7 @@ export class DynamicCharAtlas extends BaseCharAtlas { const fontStyle = glyph.italic ? 'italic' : ''; this._tmpCtx.font = `${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`; - this._tmpCtx.textBaseline = 'ideographic'; + this._tmpCtx.textBaseline = TEXT_BASELINE; this._tmpCtx.fillStyle = this._getForegroundColor(glyph).css; From 33bbc4f4b8a963288d93b73f5e4f990f61496549 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Fri, 22 Oct 2021 20:50:00 +0000 Subject: [PATCH 31/35] cache options and type _options --- src/common/services/OptionsService.ts | 62 +++++++++------------------ 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 32385b26..5f647c42 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -65,84 +65,64 @@ const CONSTRUCTOR_ONLY_OPTIONS = ['cols', 'rows']; export class OptionsService implements IOptionsService { public serviceBrand: any; - private _options: any; + private _options: ITerminalOptions; public options: ITerminalOptions; + public publicOptions: ITerminalOptions; private _onOptionChange = new EventEmitter(); public get onOptionChange(): IEvent { return this._onOptionChange.event; } constructor(options: Partial) { - this.options = { ...DEFAULT_OPTIONS }; + // set the default value of each option + this._options = { ...DEFAULT_OPTIONS }; for (const key in options) { - if (key in this.options) { + if (key in this._options) { try { const newValue = options[key]; - this.options[key] = this._sanitizeAndValidateOption(key, newValue); + this._options[key] = this._sanitizeAndValidateOption(key, newValue); } catch (e) { console.error(e); } } } - this._options = {}; - for (const propName in this.options) { - const privatePropName = `_${propName}`; - this._options[privatePropName] = this.options[propName]; - - Object.defineProperty(this.options, propName, { - get: () => { - if (!(propName in DEFAULT_OPTIONS)) { - throw new Error(`No option with key "${propName}"`); - } - return this._options[privatePropName]; - }, - set: (value: any) => { - if (!(propName in DEFAULT_OPTIONS)) { - throw new Error('No option with key "' + propName + '"'); - } - - value = this._sanitizeAndValidateOption(propName, value); - // Don't fire an option change event if they didn't change - if (this._options[privatePropName] !== value) { - this._options[privatePropName] = value; - this._onOptionChange.fire(propName); - } - } - }); - } + // set up getters and setters for each option + this.options = this._setupOptions(this._options, false); + this.publicOptions = this._setupOptions(this._options, true); } - public get publicOptions(): ITerminalOptions { - const publicOptions = { ... this.options }; - for (const propName in CONSTRUCTOR_ONLY_OPTIONS) { - const privatePropName = `_${propName}`; - Object.defineProperty(publicOptions, propName, { + private _setupOptions(options: ITerminalOptions, isPublic: boolean): ITerminalOptions { + const copiedOptions = { ... options }; + for (const propName in copiedOptions) { + Object.defineProperty(copiedOptions, propName, { get: () => { if (!(propName in DEFAULT_OPTIONS)) { throw new Error(`No option with key "${propName}"`); } - return this._options[privatePropName]; + return this._options[propName]; }, set: (value: any) => { if (!(propName in DEFAULT_OPTIONS)) { - throw new Error('No option with key "' + propName + '"'); + throw new Error(`No option with key "${propName}"`); } + // Throw an error if any constructor only option is modified // from terminal.options - if (CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { + // Modifications from anywhere else are allowed + if (isPublic && CONSTRUCTOR_ONLY_OPTIONS.includes(propName)) { throw new Error(`Option "${propName}" can only be set in the constructor`); } value = this._sanitizeAndValidateOption(propName, value); // Don't fire an option change event if they didn't change - if (this._options[privatePropName] !== value) { - this._options[privatePropName] = value; + if (this._options[propName] !== value) { + this._options[propName] = value; this._onOptionChange.fire(propName); } } }); } - return publicOptions; + return copiedOptions; } public setOption(key: string, value: any): void { From 57e6cfd500ab4cf934f77af415b7d91c385cad91 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Fri, 22 Oct 2021 20:53:06 +0000 Subject: [PATCH 32/35] setOption and getOption should look at publicOptions --- src/common/services/OptionsService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 5f647c42..a245c153 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -126,7 +126,7 @@ export class OptionsService implements IOptionsService { } public setOption(key: string, value: any): void { - this.options[key] = value; + this.publicOptions[key] = value; } private _sanitizeAndValidateOption(key: string, value: any): any { @@ -181,6 +181,6 @@ export class OptionsService implements IOptionsService { } public getOption(key: string): any { - return this.options[key]; + return this.publicOptions[key]; } } From c7ee362ae70910e0dc033e36bb63e98ac1eab7bf Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Fri, 22 Oct 2021 20:54:42 +0000 Subject: [PATCH 33/35] revert changes to interface ITerminalOptions --- src/common/services/Services.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 5124260a..56b10f73 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -199,27 +199,21 @@ export enum LogLevelEnum { OFF = 4 } export type RendererType = 'dom' | 'canvas'; -export type BellStyle = 'none' | 'sound' /* | 'visual' | 'both' */; -export type CursorStyle = 'block' | 'underline' | 'bar'; -export type FastScrollModifier = 'alt' | 'ctrl' | 'shift'; - export interface ITerminalOptions { allowProposedApi: boolean; allowTransparency: boolean; altClickMovesCursor: boolean; bellSound: string; - bellStyle: BellStyle; - cancelEvents: boolean; + bellStyle: 'none' | 'sound' /* | 'visual' | 'both' */; cols: number; - convertEol: boolean; cursorBlink: boolean; - cursorStyle: CursorStyle; + cursorStyle: 'block' | 'underline' | 'bar'; cursorWidth: number; customGlyphs: boolean; disableStdin: boolean; drawBoldTextInBrightColors: boolean; - fastScrollModifier: FastScrollModifier | undefined; + fastScrollModifier: 'alt' | 'ctrl' | 'shift' | undefined; fastScrollSensitivity: number; fontSize: number; fontFamily: string; @@ -239,13 +233,15 @@ export interface ITerminalOptions { scrollback: number; scrollSensitivity: number; tabStopWidth: number; - termName: string; theme: ITheme; windowsMode: boolean; windowOptions: IWindowOptions; wordSeparator: string; [key: string]: any; + cancelEvents: boolean; + convertEol: boolean; + termName: string; } export interface ITheme { From 645263b0acef5d2d5a0cc38c233d47bdd70cc2e3 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Sat, 23 Oct 2021 08:22:00 +0000 Subject: [PATCH 34/35] update npmignore, don't include test files --- .npmignore | 6 ++++++ addons/xterm-addon-attach/.npmignore | 6 ++++++ addons/xterm-addon-fit/.npmignore | 6 ++++++ addons/xterm-addon-ligatures/.npmignore | 6 ++++++ addons/xterm-addon-search/.npmignore | 6 ++++++ addons/xterm-addon-serialize/.npmignore | 6 ++++++ addons/xterm-addon-unicode11/.npmignore | 6 ++++++ addons/xterm-addon-web-links/.npmignore | 6 ++++++ addons/xterm-addon-webgl/.npmignore | 6 ++++++ headless/.npmignore | 6 ++++++ 10 files changed, 60 insertions(+) diff --git a/.npmignore b/.npmignore index 7b2c6b59..91fbd773 100644 --- a/.npmignore +++ b/.npmignore @@ -28,6 +28,12 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-attach/.npmignore b/addons/xterm-addon-attach/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-attach/.npmignore +++ b/addons/xterm-addon-attach/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-fit/.npmignore b/addons/xterm-addon-fit/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-fit/.npmignore +++ b/addons/xterm-addon-fit/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-ligatures/.npmignore b/addons/xterm-addon-ligatures/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-ligatures/.npmignore +++ b/addons/xterm-addon-ligatures/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-search/.npmignore b/addons/xterm-addon-search/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-search/.npmignore +++ b/addons/xterm-addon-search/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-serialize/.npmignore b/addons/xterm-addon-serialize/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-serialize/.npmignore +++ b/addons/xterm-addon-serialize/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-unicode11/.npmignore b/addons/xterm-addon-unicode11/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-unicode11/.npmignore +++ b/addons/xterm-addon-unicode11/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-web-links/.npmignore b/addons/xterm-addon-web-links/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-web-links/.npmignore +++ b/addons/xterm-addon-web-links/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/addons/xterm-addon-webgl/.npmignore b/addons/xterm-addon-webgl/.npmignore index 00b53247..b203232a 100644 --- a/addons/xterm-addon-webgl/.npmignore +++ b/addons/xterm-addon-webgl/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts diff --git a/headless/.npmignore b/headless/.npmignore index 3c9d7e8f..535e5ec3 100644 --- a/headless/.npmignore +++ b/headless/.npmignore @@ -19,5 +19,11 @@ !src/**/*.css +# Blacklist - src/ test files +src/**/*.test.ts +src/**/*.test.d.ts +src/**/*.test.js +src/**/*.test.js.map + # Whitelist - typings/ !typings/*.d.ts From 5c9adeef930b969bc822470b504ae690d82dd05e Mon Sep 17 00:00:00 2001 From: ElJeffe Date: Tue, 26 Oct 2021 11:44:52 -0400 Subject: [PATCH 35/35] Check to make sure cols & rows are INT I've noticed that if the terminal is hidden and the screen experiences a resize trigger from a blur / focus, it can cause the dimensions to be undefined. This creates an exception in Xterm.js that the values are not integers. Figured it would be ok to just check before doing a resize. --- addons/xterm-addon-fit/src/FitAddon.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-fit/src/FitAddon.ts b/addons/xterm-addon-fit/src/FitAddon.ts index f4e5c772..360397ec 100644 --- a/addons/xterm-addon-fit/src/FitAddon.ts +++ b/addons/xterm-addon-fit/src/FitAddon.ts @@ -33,7 +33,7 @@ export class FitAddon implements ITerminalAddon { public fit(): void { const dims = this.proposeDimensions(); - if (!dims || !this._terminal) { + if (!dims || !this._terminal || isNaN(dims.cols) || isNaN(dims.rows)) { return; }