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. diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index a54b4325..24020b74 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); } } } } @@ -433,26 +435,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..334016e6 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,19 @@ 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 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 { @@ -184,11 +196,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 +593,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'; 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 23290af4..f50fc4de 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; @@ -28,15 +28,32 @@ declare module 'xterm-addon-serialize' { * 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. + * @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; + } } 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; diff --git a/package.json b/package.json index 1b2bfb67..ad288f49 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", 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'); diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index ebe755bc..4afca04c 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -164,6 +164,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))); @@ -1180,7 +1181,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; } @@ -1290,6 +1293,18 @@ export class Terminal extends CoreTerminal implements ITerminal { this.viewport?.syncScrollArea(); } + public clearTextureAtlas(): void { + this._renderService?.clearTextureAtlas(); + } + + 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/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/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) { 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/src/common/InputHandler.ts b/src/common/InputHandler.ts index f2f0d0ce..9371e5f5 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -243,6 +243,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(); @@ -1956,6 +1958,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)'); 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..d7c2effc 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'). */ @@ -1444,18 +1452,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;