From 5a65fd9c6ab244637b4c76199d4c1aeb7da6c8a3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 10 Sep 2021 09:42:19 -0700 Subject: [PATCH 1/6] Disable emoji ime when screenReaderMode is on Fixes #3467 --- src/browser/Terminal.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index ebe755bc4..d28be5bf2 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -1180,7 +1180,9 @@ export class Terminal extends CoreTerminal implements ITerminal { * @param ev The input event to be handled. */ protected _inputEvent(ev: InputEvent): boolean { - if (ev.data && ev.inputType === 'insertText') { + // Only support emoji IMEs when screen reader mode is disabled as the event must bubble up to + // support reading out character input which can doubling up input characters + if (ev.data && ev.inputType === 'insertText' && !this.optionsService.options.screenReaderMode) { if (this._keyPressHandled) { return false; } From db6b3c4bcc4cf0934a71752e9c13ff2ade4174cd Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 10 Sep 2021 09:44:29 -0700 Subject: [PATCH 2/6] v4.14.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1b2bfb672..ad288f494 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "xterm", "description": "Full xterm terminal, in your browser", - "version": "4.14.0", + "version": "4.14.1", "main": "lib/xterm.js", "style": "css/xterm.css", "types": "typings/xterm.d.ts", 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 3/6] 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 a54b43257..d692c8189 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 bb66f37b2..c8593b72c 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 b55ee303d..a29dbb286 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 4/6] 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 c8593b72c..5fc1bfaf1 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 2e4e29ad73174757632be34fb0d0c11377e3e803 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Wed, 22 Sep 2021 08:47:36 +0000 Subject: [PATCH 5/6] 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 a54b43257..41195a7e0 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 13a321261..84b715e86 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 ba2be9881..6cf34bf85 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 6/6] 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 bb66f37b2..975252261 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';