From fc46d69a570839149a5720a1b72334ef0a9bc7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sat, 3 Sep 2022 23:52:30 +0200 Subject: [PATCH 1/7] add protection flag to DECSED/DECSEL, add DECSCA --- src/common/InputHandler.ts | 54 +++++++++++++++++++++------------ src/common/Types.d.ts | 4 +-- src/common/buffer/BufferLine.ts | 35 +++++++++++++++++++-- src/common/buffer/Constants.ts | 5 +-- 4 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 8d55f1bbb9..bf74446e19 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -334,10 +334,10 @@ export class InputHandler extends Disposable implements IInputHandler { this._parser.registerCsiHandler({ final: 'G' }, params => this.cursorCharAbsolute(params)); this._parser.registerCsiHandler({ final: 'H' }, params => this.cursorPosition(params)); this._parser.registerCsiHandler({ final: 'I' }, params => this.cursorForwardTab(params)); - this._parser.registerCsiHandler({ final: 'J' }, params => this.eraseInDisplay(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'J' }, params => this.eraseInDisplay(params)); - this._parser.registerCsiHandler({ final: 'K' }, params => this.eraseInLine(params)); - this._parser.registerCsiHandler({ prefix: '?', final: 'K' }, params => this.eraseInLine(params)); + this._parser.registerCsiHandler({ final: 'J' }, params => this.eraseInDisplay(params, false)); + this._parser.registerCsiHandler({ prefix: '?', final: 'J' }, params => this.eraseInDisplay(params, true)); + this._parser.registerCsiHandler({ final: 'K' }, params => this.eraseInLine(params, false)); + this._parser.registerCsiHandler({ prefix: '?', final: 'K' }, params => this.eraseInLine(params, true)); this._parser.registerCsiHandler({ final: 'L' }, params => this.insertLines(params)); this._parser.registerCsiHandler({ final: 'M' }, params => this.deleteLines(params)); this._parser.registerCsiHandler({ final: 'P' }, params => this.deleteChars(params)); @@ -369,6 +369,7 @@ export class InputHandler extends Disposable implements IInputHandler { this._parser.registerCsiHandler({ final: 'u' }, params => this.restoreCursor(params)); this._parser.registerCsiHandler({ intermediates: '\'', final: '}' }, params => this.insertColumns(params)); this._parser.registerCsiHandler({ intermediates: '\'', final: '~' }, params => this.deleteColumns(params)); + this._parser.registerCsiHandler({ intermediates: '"', final: 'q' }, params => this.selectProtected(params)); /** * execute handler @@ -1206,6 +1207,18 @@ export class InputHandler extends Disposable implements IInputHandler { return true; } + /** + * CSI Ps " q Select Character Protection Attribute (DECSCA). + * + * @vt: #Y CSI DECSCA "Select Character Protection Attribute" "CSI Ps " q" "Whether DECSED and DECSEL can erase (0=default, 2) or not (1)." + */ + public selectProtected(params: IParams): boolean { + const p = params.params[0]; + if (p === 1) this._curAttrData.bg |= BgFlags.PROTECTED; + if (p === 2 || p === 0) this._curAttrData.bg &= ~BgFlags.PROTECTED; + return true; + } + /** * Helper method to erase cells in a terminal row. @@ -1215,13 +1228,14 @@ export class InputHandler extends Disposable implements IInputHandler { * @param end end - 1 is last erased cell * @param cleanWrap clear the isWrapped flag */ - private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false): void { + private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false, protect: boolean = false): void { const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; line.replaceCells( start, end, this._activeBuffer.getNullCell(this._eraseAttrData()), - this._eraseAttrData() + this._eraseAttrData(), + protect ); if (clearWrap) { line.isWrapped = false; @@ -1233,9 +1247,9 @@ export class InputHandler extends Disposable implements IInputHandler { * The cell gets replaced with the eraseChar of the terminal and the isWrapped property is set to false. * @param y row index */ - private _resetBufferLine(y: number): void { + private _resetBufferLine(y: number, protect: boolean = false): void { const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.fill(this._activeBuffer.getNullCell(this._eraseAttrData())); + line.fill(this._activeBuffer.getNullCell(this._eraseAttrData()), protect); this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase + y); line.isWrapped = false; } @@ -1262,18 +1276,18 @@ export class InputHandler extends Disposable implements IInputHandler { * | 2 | Erase complete viewport. | * | 3 | Erase scrollback. | * - * @vt: #P[Protection attributes are not supported.] CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Currently the same as ED." + * @vt: #Y CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Same as ED with respecting protection flag." */ - public eraseInDisplay(params: IParams): boolean { + public eraseInDisplay(params: IParams, protect: boolean = false): boolean { this._restrictCursor(this._bufferService.cols); let j; switch (params.params[0]) { case 0: j = this._activeBuffer.y; this._dirtyRowService.markDirty(j); - this._eraseInBufferLine(j++, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0); + this._eraseInBufferLine(j++, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0, protect); for (; j < this._bufferService.rows; j++) { - this._resetBufferLine(j); + this._resetBufferLine(j, protect); } this._dirtyRowService.markDirty(j); break; @@ -1281,13 +1295,13 @@ export class InputHandler extends Disposable implements IInputHandler { j = this._activeBuffer.y; this._dirtyRowService.markDirty(j); // Deleted front part of line and everything before. This line will no longer be wrapped. - this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true); + this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true, protect); if (this._activeBuffer.x + 1 >= this._bufferService.cols) { // Deleted entire previous line. This next line can no longer be wrapped. this._activeBuffer.lines.get(j + 1)!.isWrapped = false; } while (j--) { - this._resetBufferLine(j); + this._resetBufferLine(j, protect); } this._dirtyRowService.markDirty(0); break; @@ -1295,7 +1309,7 @@ export class InputHandler extends Disposable implements IInputHandler { j = this._bufferService.rows; this._dirtyRowService.markDirty(j - 1); while (j--) { - this._resetBufferLine(j); + this._resetBufferLine(j, protect); } this._dirtyRowService.markDirty(0); break; @@ -1334,19 +1348,19 @@ export class InputHandler extends Disposable implements IInputHandler { * | 1 | Erase from the beginning of the line through the cursor. | * | 2 | Erase complete line. | * - * @vt: #P[Protection attributes are not supported.] CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Currently the same as EL." + * @vt: #Y CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Same as EL with respecting protecting flag." */ - public eraseInLine(params: IParams): boolean { + public eraseInLine(params: IParams, protect: boolean = false): boolean { this._restrictCursor(this._bufferService.cols); switch (params.params[0]) { case 0: - this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0); + this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0, protect); break; case 1: - this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1, false); + this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1, false, protect); break; case 2: - this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols, true); + this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols, true, protect); break; } this._dirtyRowService.markDirty(this._activeBuffer.y); diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 7d15d6a18c..3139911695 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -203,9 +203,9 @@ export interface IBufferLine { addCodepointToCell(index: number, codePoint: number): void; insertCells(pos: number, n: number, ch: ICellData, eraseAttr?: IAttributeData): void; deleteCells(pos: number, n: number, fill: ICellData, eraseAttr?: IAttributeData): void; - replaceCells(start: number, end: number, fill: ICellData, eraseAttr?: IAttributeData): void; + replaceCells(start: number, end: number, fill: ICellData, eraseAttr?: IAttributeData, protect?: boolean): void; resize(cols: number, fill: ICellData): void; - fill(fillCellData: ICellData): void; + fill(fillCellData: ICellData, protect?: boolean): void; copyFrom(line: IBufferLine): void; clone(): IBufferLine; getTrimmedLength(): number; diff --git a/src/common/buffer/BufferLine.ts b/src/common/buffer/BufferLine.ts index eed87e6b07..ceb5377c78 100644 --- a/src/common/buffer/BufferLine.ts +++ b/src/common/buffer/BufferLine.ts @@ -168,6 +168,11 @@ export class BufferLine implements IBufferLine { return ''; } + /** Get state of protected flag. */ + public isProtected(index: number): number { + return this._data[index * CELL_SIZE + Cell.BG] & BgFlags.PROTECTED; + } + /** * Load data at `index` into `cell`. This is used to access cells in a way that's more friendly * to GC as it significantly reduced the amount of new objects/references needed. @@ -298,7 +303,24 @@ export class BufferLine implements IBufferLine { } } - public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData): void { + public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData, protect: boolean = false): void { + // full branching on protect==true, hopefully getting fast JIT for standard case + if (protect) { + if (start && this.getWidth(start - 1) === 2 && !this.isProtected(start - 1)) { + this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); + } + if (end < this.length && this.getWidth(end - 1) === 2 && !this.isProtected(end)) { + this.setCellFromCodePoint(end, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); + } + while (start < end && start < this.length) { + if (!this.isProtected(start)) { + this.setCell(start, fillCellData); + } + start++; + } + return; + } + // handle fullwidth at start: reset cell one to the left if start is second cell of a wide char if (start && this.getWidth(start - 1) === 2) { this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); @@ -352,7 +374,16 @@ export class BufferLine implements IBufferLine { } /** fill a line with fillCharData */ - public fill(fillCellData: ICellData): void { + public fill(fillCellData: ICellData, protect: boolean = false): void { + // full branching on protect==true, hopefully getting fast JIT for standard case + if (protect) { + for (let i = 0; i < this.length; ++i) { + if (!this.isProtected(i)) { + this.setCell(i, fillCellData); + } + } + return; + } this._combined = {}; this._extendedAttrs = {}; for (let i = 0; i < this.length; ++i) { diff --git a/src/common/buffer/Constants.ts b/src/common/buffer/Constants.ts index 0dfa86fd1e..25999bcd2b 100644 --- a/src/common/buffer/Constants.ts +++ b/src/common/buffer/Constants.ts @@ -123,11 +123,12 @@ export const enum FgFlags { export const enum BgFlags { /** - * bit 27..32 (upper 3 unused) + * bit 27..32 (upper 2 unused) */ ITALIC = 0x4000000, DIM = 0x8000000, - HAS_EXTENDED = 0x10000000 + HAS_EXTENDED = 0x10000000, + PROTECTED = 0x20000000 } export const enum ExtFlags { From 2608db272899410a22c944cdd842e036ff121b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 4 Sep 2022 11:04:07 +0200 Subject: [PATCH 2/7] unit tests, fix DECRQSS report --- src/common/InputHandler.test.ts | 44 ++++++++++++++++++++++++++++++ src/common/InputHandler.ts | 20 ++++++++------ src/common/Types.d.ts | 1 + src/common/buffer/AttributeData.ts | 1 + 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index 2fa4ac2fa2..f86006eb46 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -2146,6 +2146,50 @@ describe('InputHandler', () => { }); }); }); + + describe('DECSCA and DECSED/DECSEL', () => { + it('default is unprotected', async () => { + await inputHandler.parseP('some text'); + await inputHandler.parseP('\x1b[?2K'); + assert.deepEqual(getLines(bufferService, 2), ['', '']); + await inputHandler.parseP('some text'); + await inputHandler.parseP('\x1b[?2J'); + assert.deepEqual(getLines(bufferService, 2), ['', '']); + }); + it('DECSCA 1 with DECSEL', async () => { + await inputHandler.parseP('###\x1b[1"qlineerase\x1b[0"q***'); + await inputHandler.parseP('\x1b[?2K'); + assert.deepEqual(getLines(bufferService, 2), [' lineerase', '']); + // normal EL works as before + await inputHandler.parseP('\x1b[2K'); + assert.deepEqual(getLines(bufferService, 2), ['', '']); + }); + it('DECSCA 1 with DECSED', async () => { + await inputHandler.parseP('###\x1b[1"qdisplayerase\x1b[0"q***'); + await inputHandler.parseP('\x1b[?2J'); + assert.deepEqual(getLines(bufferService, 2), [' displayerase', '']); + // normal ED works as before + await inputHandler.parseP('\x1b[2J'); + assert.deepEqual(getLines(bufferService, 2), ['', '']); + }); + it('DECRQSS reports correct DECSCA state', async () => { + const sendStack: string[] = []; + coreService.onData(d => sendStack.push(d)); + // DCS $ q " q ST + await inputHandler.parseP('\x1bP$q"q\x1b\\'); + console.log(sendStack); + // default - DECSCA unset (0 or 2) + assert.deepEqual(sendStack.pop(), '\x1bP1$r0"q\x1b\\'); + // DECSCA 1 - protected set + await inputHandler.parseP('###\x1b[1"q'); + await inputHandler.parseP('\x1bP$q"q\x1b\\'); + assert.deepEqual(sendStack.pop(), '\x1bP1$r1"q\x1b\\'); + // DECSCA 2 - protected reset (same as 0) + await inputHandler.parseP('###\x1b[2"q'); + await inputHandler.parseP('\x1bP$q"q\x1b\\'); + assert.deepEqual(sendStack.pop(), '\x1bP1$r0"q\x1b\\'); // reported as DECSCA 0 + }); + }); }); diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index bf74446e19..886bb7e3b6 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -123,13 +123,12 @@ const SLOW_ASYNC_LIMIT = 5000; * | Graphic Rendition (SGR) | `DCS $ q m ST` | always reporting `0m` (currently broken) | * | Top and Bottom Margins (DECSTBM) | `DCS $ q r ST` | `Ps ; Ps r` | * | Cursor Style (DECSCUSR) | `DCS $ q SP q ST` | `Ps SP q` | - * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | always reporting `0 " q` (DECSCA is unsupported) | + * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | `Ps " q` (DECSCA 2 is reported as 0) | * | Conformance Level (DECSCL) | `DCS $ q " p ST` | always reporting `61 ; 1 " p` (DECSCL is unsupported) | * * * TODO: * - fix SGR report - * - either implement DECSCA or remove the report * - either check which conformance is better suited or remove the report completely * --> we are currently a mixture of all up to VT400 but dont follow anyone strictly */ @@ -137,10 +136,11 @@ class DECRQSS implements IDcsHandler { private _data: Uint32Array = new Uint32Array(0); constructor( - private _bufferService: IBufferService, - private _coreService: ICoreService, - private _logService: ILogService, - private _optionsService: IOptionsService + private readonly _ih: InputHandler, + private readonly _bufferService: IBufferService, + private readonly _coreService: ICoreService, + private readonly _logService: ILogService, + private readonly _optionsService: IOptionsService ) { } public hook(params: IParams): void { @@ -161,7 +161,8 @@ class DECRQSS implements IDcsHandler { switch (data) { // valid: DCS 1 $ r Pt ST (xterm) case '"q': // DECSCA - this._coreService.triggerDataEvent(`${C0.ESC}P1$r0"q${C0.ESC}\\`); + const prot = this._ih.getAttrData().isProtected() ? 1 : 0; + this._coreService.triggerDataEvent(`${C0.ESC}P1$r${prot}"q${C0.ESC}\\`); break; case '"p': // DECSCL this._coreService.triggerDataEvent(`${C0.ESC}P1$r61;1"p${C0.ESC}\\`); @@ -172,7 +173,7 @@ class DECRQSS implements IDcsHandler { this._coreService.triggerDataEvent(`${C0.ESC}P1$r${pt}${C0.ESC}\\`); break; case 'm': // SGR - // TODO: report real settings instead of 0m + // FIXME: report real settings instead of 0m this._coreService.triggerDataEvent(`${C0.ESC}P1$r0m${C0.ESC}\\`); break; case ' q': // DECSCUSR @@ -233,6 +234,7 @@ export class InputHandler extends Disposable implements IInputHandler { protected _iconNameStack: string[] = []; private _curAttrData: IAttributeData = DEFAULT_ATTR_DATA.clone(); + public getAttrData(): IAttributeData { return this._curAttrData; } private _eraseAttrDataInternal: IAttributeData = DEFAULT_ATTR_DATA.clone(); private _activeBuffer: IBuffer; @@ -482,7 +484,7 @@ export class InputHandler extends Disposable implements IInputHandler { /** * DCS handler */ - this._parser.registerDcsHandler({ intermediates: '$', final: 'q' }, new DECRQSS(this._bufferService, this._coreService, this._logService, this._optionsService)); + this._parser.registerDcsHandler({ intermediates: '$', final: 'q' }, new DECRQSS(this, this._bufferService, this._coreService, this._logService, this._optionsService)); } public dispose(): void { diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 3139911695..f559719e09 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -150,6 +150,7 @@ export interface IAttributeData { isItalic(): number; isDim(): number; isStrikethrough(): number; + isProtected(): number; // color modes getFgColorMode(): number; diff --git a/src/common/buffer/AttributeData.ts b/src/common/buffer/AttributeData.ts index 3af3d29393..c9f4cd61f3 100644 --- a/src/common/buffer/AttributeData.ts +++ b/src/common/buffer/AttributeData.ts @@ -46,6 +46,7 @@ export class AttributeData implements IAttributeData { public isItalic(): number { return this.bg & BgFlags.ITALIC; } public isDim(): number { return this.bg & BgFlags.DIM; } public isStrikethrough(): number { return this.fg & FgFlags.STRIKETHROUGH; } + public isProtected(): number { return this.bg & BgFlags.PROTECTED; } // color modes public getFgColorMode(): number { return this.fg & Attributes.CM_MASK; } From d511720f63a7fa71a45d8e3297523d557565050e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 4 Sep 2022 11:34:31 +0200 Subject: [PATCH 3/7] reshape DECRQSS --- src/common/InputHandler.test.ts | 1 - src/common/InputHandler.ts | 189 +++++++++++++------------------- 2 files changed, 76 insertions(+), 114 deletions(-) diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index f86006eb46..1d4d4effc3 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -2177,7 +2177,6 @@ describe('InputHandler', () => { coreService.onData(d => sendStack.push(d)); // DCS $ q " q ST await inputHandler.parseP('\x1bP$q"q\x1b\\'); - console.log(sendStack); // default - DECSCA unset (0 or 2) assert.deepEqual(sendStack.pop(), '\x1bP1$r0"q\x1b\\'); // DECSCA 1 - protected set diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 886bb7e3b6..f69fabe41c 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -102,118 +102,6 @@ export enum WindowsOptionsReportType { // create a warning log if an async handler takes longer than the limit (in ms) const SLOW_ASYNC_LIMIT = 5000; -/** - * DCS subparser implementations - */ - -/** - * DCS $ q Pt ST - * DECRQSS (https://vt100.net/docs/vt510-rm/DECRQSS.html) - * Request Status String (DECRQSS), VT420 and up. - * Response: DECRPSS (https://vt100.net/docs/vt510-rm/DECRPSS.html) - * - * @vt: #P[See limited support below.] DCS DECRQSS "Request Selection or Setting" "DCS $ q Pt ST" "Request several terminal settings." - * Response is in the form `ESC P 1 $ r Pt ST` for valid requests, where `Pt` contains the corresponding CSI string, - * `ESC P 0 ST` for invalid requests. - * - * Supported requests and responses: - * - * | Type | Request | Response (`Pt`) | - * | -------------------------------- | ----------------- | ----------------------------------------------------- | - * | Graphic Rendition (SGR) | `DCS $ q m ST` | always reporting `0m` (currently broken) | - * | Top and Bottom Margins (DECSTBM) | `DCS $ q r ST` | `Ps ; Ps r` | - * | Cursor Style (DECSCUSR) | `DCS $ q SP q ST` | `Ps SP q` | - * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | `Ps " q` (DECSCA 2 is reported as 0) | - * | Conformance Level (DECSCL) | `DCS $ q " p ST` | always reporting `61 ; 1 " p` (DECSCL is unsupported) | - * - * - * TODO: - * - fix SGR report - * - either check which conformance is better suited or remove the report completely - * --> we are currently a mixture of all up to VT400 but dont follow anyone strictly - */ -class DECRQSS implements IDcsHandler { - private _data: Uint32Array = new Uint32Array(0); - - constructor( - private readonly _ih: InputHandler, - private readonly _bufferService: IBufferService, - private readonly _coreService: ICoreService, - private readonly _logService: ILogService, - private readonly _optionsService: IOptionsService - ) { } - - public hook(params: IParams): void { - this._data = new Uint32Array(0); - } - - public put(data: Uint32Array, start: number, end: number): void { - this._data = concat(this._data, data.subarray(start, end)); - } - - public unhook(success: boolean): boolean { - if (!success) { - this._data = new Uint32Array(0); - return true; - } - const data = utf32ToString(this._data); - this._data = new Uint32Array(0); - switch (data) { - // valid: DCS 1 $ r Pt ST (xterm) - case '"q': // DECSCA - const prot = this._ih.getAttrData().isProtected() ? 1 : 0; - this._coreService.triggerDataEvent(`${C0.ESC}P1$r${prot}"q${C0.ESC}\\`); - break; - case '"p': // DECSCL - this._coreService.triggerDataEvent(`${C0.ESC}P1$r61;1"p${C0.ESC}\\`); - break; - case 'r': // DECSTBM - const pt = '' + (this._bufferService.buffer.scrollTop + 1) + - ';' + (this._bufferService.buffer.scrollBottom + 1) + 'r'; - this._coreService.triggerDataEvent(`${C0.ESC}P1$r${pt}${C0.ESC}\\`); - break; - case 'm': // SGR - // FIXME: report real settings instead of 0m - this._coreService.triggerDataEvent(`${C0.ESC}P1$r0m${C0.ESC}\\`); - break; - case ' q': // DECSCUSR - const STYLES: { [key: string]: number } = { 'block': 2, 'underline': 4, 'bar': 6 }; - let style = STYLES[this._optionsService.rawOptions.cursorStyle]; - style -= this._optionsService.rawOptions.cursorBlink ? 1 : 0; - this._coreService.triggerDataEvent(`${C0.ESC}P1$r${style} q${C0.ESC}\\`); - break; - default: - // invalid: DCS 0 $ r Pt ST (xterm) - this._logService.debug('Unknown DCS $q %s', data); - this._coreService.triggerDataEvent(`${C0.ESC}P0$r${C0.ESC}\\`); - } - return true; - } -} - -/** - * DCS Ps; Ps| Pt ST - * DECUDK (https://vt100.net/docs/vt510-rm/DECUDK.html) - * not supported - * - * @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps | Pt ST" "Definitions for user-defined keys." - */ - -/** - * DCS + q Pt ST (xterm) - * Request Terminfo String - * not implemented - * - * @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." - */ - -/** - * DCS + p Pt ST (xterm) - * Set Terminfo Data - * not supported - * - * @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." - */ /** * The terminal's standard implementation of IInputHandler, this handles all @@ -484,7 +372,7 @@ export class InputHandler extends Disposable implements IInputHandler { /** * DCS handler */ - this._parser.registerDcsHandler({ intermediates: '$', final: 'q' }, new DECRQSS(this, this._bufferService, this._coreService, this._logService, this._optionsService)); + this._parser.registerDcsHandler({ intermediates: '$', final: 'q' }, new DcsHandler((data, params) => this.requestStatusString(data, params))); } public dispose(): void { @@ -3313,4 +3201,79 @@ export class InputHandler extends Disposable implements IInputHandler { this._setCursor(0, 0); return true; } + + + /** + * DCS $ q Pt ST + * DECRQSS (https://vt100.net/docs/vt510-rm/DECRQSS.html) + * Request Status String (DECRQSS), VT420 and up. + * Response: DECRPSS (https://vt100.net/docs/vt510-rm/DECRPSS.html) + * + * @vt: #P[See limited support below.] DCS DECRQSS "Request Selection or Setting" "DCS $ q Pt ST" "Request several terminal settings." + * Response is in the form `ESC P 1 $ r Pt ST` for valid requests, where `Pt` contains the corresponding CSI string, + * `ESC P 0 ST` for invalid requests. + * + * Supported requests and responses: + * + * | Type | Request | Response (`Pt`) | + * | -------------------------------- | ----------------- | ----------------------------------------------------- | + * | Graphic Rendition (SGR) | `DCS $ q m ST` | always reporting `0m` (currently broken) | + * | Top and Bottom Margins (DECSTBM) | `DCS $ q r ST` | `Ps ; Ps r` | + * | Cursor Style (DECSCUSR) | `DCS $ q SP q ST` | `Ps SP q` | + * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | `Ps " q` (DECSCA 2 is reported as 0) | + * | Conformance Level (DECSCL) | `DCS $ q " p ST` | always reporting `61 ; 1 " p` (DECSCL is unsupported) | + * + * + * TODO: + * - fix SGR report + * - either check which conformance is better suited or remove the report completely + * --> we are currently a mixture of all up to VT400 but dont follow anyone strictly + */ + public requestStatusString(data: string, params: IParams): boolean { + const f = (s: string): boolean => { + this._coreService.triggerDataEvent(`${C0.ESC}${s}${C0.ESC}\\`); + return true; + }; + + // access helpers + const b = this._bufferService.buffer; + const opts = this._optionsService.rawOptions; + const STYLES: { [key: string]: number } = { 'block': 2, 'underline': 4, 'bar': 6 }; + + if (data === '"q') return f(`P1$r${this._curAttrData.isProtected() ? 1 : 0}"q`); + if (data === '"p') return f(`P1$r61;1"p`); + if (data === 'r') return f(`P1$r${b.scrollTop + 1};${b.scrollBottom + 1}r`); + if (data === 'm') return f(`P1$r0m`); // FIXME: report real settings instead of 0m + if (data === ' q') return f(`P1$r${STYLES[opts.cursorStyle] - (opts.cursorBlink ? 1 : 0)} q`); + return f(`P0$r`); + } } + + +/** + * Unimplemented DCS functions (kept for documentation purpose) + */ + +/** + * DCS Ps; Ps| Pt ST + * DECUDK (https://vt100.net/docs/vt510-rm/DECUDK.html) + * not supported + * + * @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps | Pt ST" "Definitions for user-defined keys." + */ + +/** + * DCS + q Pt ST (xterm) + * Request Terminfo String + * not implemented + * + * @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." + */ + +/** + * DCS + p Pt ST (xterm) + * Set Terminfo Data + * not supported + * + * @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." + */ From 68fe100841f16d9724675413eabbe399ec76df1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 4 Sep 2022 11:51:41 +0200 Subject: [PATCH 4/7] cleanup --- src/common/InputHandler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index f69fabe41c..64352d2829 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -3243,7 +3243,8 @@ export class InputHandler extends Disposable implements IInputHandler { if (data === '"q') return f(`P1$r${this._curAttrData.isProtected() ? 1 : 0}"q`); if (data === '"p') return f(`P1$r61;1"p`); if (data === 'r') return f(`P1$r${b.scrollTop + 1};${b.scrollBottom + 1}r`); - if (data === 'm') return f(`P1$r0m`); // FIXME: report real settings instead of 0m + // FIXME: report real SGR settings instead of 0m + if (data === 'm') return f(`P1$r0m`); if (data === ' q') return f(`P1$r${STYLES[opts.cursorStyle] - (opts.cursorBlink ? 1 : 0)} q`); return f(`P0$r`); } From 318b60418eb5cc9089723aaf5b5d7980f8e90035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 4 Sep 2022 12:54:27 +0200 Subject: [PATCH 5/7] cleanup vtfeaures docs --- bin/extract_vtfeatures.js | 13 +++++---- src/common/InputHandler.ts | 55 +++++++++++--------------------------- 2 files changed, 23 insertions(+), 45 deletions(-) diff --git a/bin/extract_vtfeatures.js b/bin/extract_vtfeatures.js index 9b5ab898f9..60979cce4d 100644 --- a/bin/extract_vtfeatures.js +++ b/bin/extract_vtfeatures.js @@ -82,14 +82,15 @@ This document lists xterm.js' support of terminal sequences. The sequences are g - OSC - Operating System Command: sequence starting with \`ESC ]\` (7bit) or OSC (\`\\x9D\`, 8bit) Application Program Command (APC), Privacy Message (PM) and Start of String (SOS) are recognized but not supported, -any sequence of these types will be ignored. They are also not hookable by the API. +any sequence of these types will be silently ignored. They are also not hookable by the API. -Note that the list only contains sequences implemented in xterm.js' core codebase. Missing sequences are either -not supported or unstable/experimental. Furthermore addons or integrations can provide additional custom sequences. +Note that the list only marks sequences implemented in xterm.js' core codebase as supported. Missing sequences are either +not supported or unstable/experimental. Furthermore addons or integrations can provide additional custom sequences +(denoted as "External" where known). To denote the sequences the tables use the same abbreviations as xterm does: - \`Ps\`: A single (usually optional) numeric parameter, composed of one or more decimal digits. -- \`Pm\`: A multiple numeric parameter composed of any number of single numeric parameters, separated by ; character(s), +- \`Pm\`: Multiple numeric parameters composed of any number of single numeric parameters, separated by ; character(s), e.g. \` Ps ; Ps ; ... \`. - \`Pt\`: A text parameter composed of printable characters. Note that for most commands with \`Pt\` only ASCII printables are specified to work. Additionally the parser will let pass any codepoint greater than C1 as printable. @@ -334,7 +335,9 @@ const MACRO = [ // #P[reason] - partial support with a reason as title [/#P\[(.*?)\]/g, (s, p1) => `Partial`], // #B[reason] - supported but broken in a certain way, reason in title - [/#B\[(.*?)\]/g, (s, p1) => `Broken`] + [/#B\[(.*?)\]/g, (s, p1) => `Broken`], + // #E[notes] - support via external resource, eg. addon + [/#E\[(.*?)\]/g, (s, p1) => `External`] ]; function applyMacros(s) { diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 64352d2829..328070ab04 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -47,10 +47,13 @@ const GLEVEL: { [key: string]: number } = { '(': 0, ')': 1, '*': 2, '+': 3, '-': // @vt: #Y C0 ESC "Escape" "\e, \x1B" "Start of a sequence. Cancels any other sequence." /** - * Document common VT features here that are currently unsupported + * Document xterm VT features here that are currently unsupported */ -// @vt: #N DCS SIXEL "SIXEL Graphics" "DCS Ps ; Ps ; Ps ; q Pt ST" "Draw SIXEL image starting at cursor position." -// @vt: #N OSC 1 "Set Icon Name" "OSC 1 ; Pt BEL" "Set icon name." +// @vt: #E[Supported via xterm-addon-image.] DCS SIXEL "SIXEL Graphics" "DCS Ps ; Ps ; Ps ; q Pt ST" "Draw SIXEL image." +// @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps \| Pt ST" "Definitions for user-defined keys." +// @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." +// @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." +// @vt: #N OSC 1 "Set Icon Name" "OSC 1 ; Pt BEL" "Set icon name." /** * Max length of the UTF32 input buffer. Real memory consumption is 4 times higher. @@ -2281,7 +2284,7 @@ export class InputHandler extends Disposable implements IInputHandler { * | 7 | Inverse. Flips foreground and background color. | #Y | * | 8 | Invisible (hidden). | #Y | * | 9 | Crossed-out characters (strikethrough). | #Y | - * | 21 | Doubly underlined. | #P[Currently outputs a single underline.] | + * | 21 | Doubly underlined. | #Y | * | 22 | Normal (neither bold nor faint). | #Y | * | 23 | No italic. | #Y | * | 24 | Not underlined. | #Y | @@ -2309,6 +2312,7 @@ export class InputHandler extends Disposable implements IInputHandler { * | 47 | Background color: White. | #Y | * | 48 | Background color: Extended color. | #P[Support for RGB and indexed colors, see below.] | * | 49 | Background color: Default (original). | #Y | + * | 58 | Underline color: Extended color. | #P[Support for RGB and indexed colors, see below.] | * | 90 - 97 | Bright foreground color (analogous to 30 - 37). | #Y | * | 100 - 107 | Bright background color (analogous to 40 - 47). | #Y | * @@ -2318,13 +2322,13 @@ export class InputHandler extends Disposable implements IInputHandler { * | ------ | ------------------------------------------------------------- | ------- | * | 0 | No underline. Same as `SGR 24 m`. | #Y | * | 1 | Single underline. Same as `SGR 4 m`. | #Y | - * | 2 | Double underline. | #P[Currently outputs a single underline.] | - * | 3 | Curly underline. | #P[Currently outputs a single underline.] | - * | 4 | Dotted underline. | #P[Currently outputs a single underline.] | - * | 5 | Dashed underline. | #P[Currently outputs a single underline.] | + * | 2 | Double underline. | #Y | + * | 3 | Curly underline. | #Y | + * | 4 | Dotted underline. | #Y | + * | 5 | Dashed underline. | #Y | * | other | Single underline. Same as `SGR 4 m`. | #Y | * - * Extended colors are supported for foreground (Ps=38) and background (Ps=48) as follows: + * Extended colors are supported for foreground (Ps=38), background (Ps=48) and underline (Ps=58) as follows: * * | Ps + 1 | Meaning | Support | * | ------ | ------------------------------------------------------------- | ------- | @@ -3209,7 +3213,7 @@ export class InputHandler extends Disposable implements IInputHandler { * Request Status String (DECRQSS), VT420 and up. * Response: DECRPSS (https://vt100.net/docs/vt510-rm/DECRPSS.html) * - * @vt: #P[See limited support below.] DCS DECRQSS "Request Selection or Setting" "DCS $ q Pt ST" "Request several terminal settings." + * @vt: #P[Limited support, see below.] DCS DECRQSS "Request Selection or Setting" "DCS $ q Pt ST" "Request several terminal settings." * Response is in the form `ESC P 1 $ r Pt ST` for valid requests, where `Pt` contains the corresponding CSI string, * `ESC P 0 ST` for invalid requests. * @@ -3220,7 +3224,7 @@ export class InputHandler extends Disposable implements IInputHandler { * | Graphic Rendition (SGR) | `DCS $ q m ST` | always reporting `0m` (currently broken) | * | Top and Bottom Margins (DECSTBM) | `DCS $ q r ST` | `Ps ; Ps r` | * | Cursor Style (DECSCUSR) | `DCS $ q SP q ST` | `Ps SP q` | - * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | `Ps " q` (DECSCA 2 is reported as 0) | + * | Protection Attribute (DECSCA) | `DCS $ q " q ST` | `Ps " q` (DECSCA 2 is reported as Ps = 0) | * | Conformance Level (DECSCL) | `DCS $ q " p ST` | always reporting `61 ; 1 " p` (DECSCL is unsupported) | * * @@ -3249,32 +3253,3 @@ export class InputHandler extends Disposable implements IInputHandler { return f(`P0$r`); } } - - -/** - * Unimplemented DCS functions (kept for documentation purpose) - */ - -/** - * DCS Ps; Ps| Pt ST - * DECUDK (https://vt100.net/docs/vt510-rm/DECUDK.html) - * not supported - * - * @vt: #N DCS DECUDK "User Defined Keys" "DCS Ps ; Ps | Pt ST" "Definitions for user-defined keys." - */ - -/** - * DCS + q Pt ST (xterm) - * Request Terminfo String - * not implemented - * - * @vt: #N DCS XTGETTCAP "Request Terminfo String" "DCS + q Pt ST" "Request Terminfo String." - */ - -/** - * DCS + p Pt ST (xterm) - * Set Terminfo Data - * not supported - * - * @vt: #N DCS XTSETTCAP "Set Terminfo Data" "DCS + p Pt ST" "Set Terminfo Data." - */ From e72e575c0fe437b3c1c6dc57d10983ec860edeb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Sun, 4 Sep 2022 13:15:47 +0200 Subject: [PATCH 6/7] fix typo in docs --- src/common/InputHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 328070ab04..7b53040164 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -2060,7 +2060,7 @@ export class InputHandler extends Disposable implements IInputHandler { * | 1005 | Disable UTF-8 Mouse Mode. | #N | * | 1006 | Disable SGR Mouse Mode. | #Y | * | 1015 | Disable urxvt Mouse Mode. | #N | - * | 1006 | Disable SGR-Pixels Mouse Mode. | #Y | + * | 1016 | Disable SGR-Pixels Mouse Mode. | #Y | * | 1047 | Use Normal Screen Buffer (clearing screen if in alt). | #Y | * | 1048 | Restore cursor as in DECRC. | #Y | * | 1049 | Use Normal Screen Buffer and restore cursor. | #Y | From b01a94f5bb4c4bfd0dd9d4ee2a5155657295c6d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Wed, 7 Sep 2022 19:47:28 +0200 Subject: [PATCH 7/7] rename to respectProtect --- src/common/InputHandler.ts | 28 ++++++++++++++-------------- src/common/Types.d.ts | 4 ++-- src/common/buffer/BufferLine.ts | 12 ++++++------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 7b53040164..cdaa377ed8 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -1121,14 +1121,14 @@ export class InputHandler extends Disposable implements IInputHandler { * @param end end - 1 is last erased cell * @param cleanWrap clear the isWrapped flag */ - private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false, protect: boolean = false): void { + private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false, respectProtect: boolean = false): void { const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; line.replaceCells( start, end, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData(), - protect + respectProtect ); if (clearWrap) { line.isWrapped = false; @@ -1140,9 +1140,9 @@ export class InputHandler extends Disposable implements IInputHandler { * The cell gets replaced with the eraseChar of the terminal and the isWrapped property is set to false. * @param y row index */ - private _resetBufferLine(y: number, protect: boolean = false): void { + private _resetBufferLine(y: number, respectProtect: boolean = false): void { const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; - line.fill(this._activeBuffer.getNullCell(this._eraseAttrData()), protect); + line.fill(this._activeBuffer.getNullCell(this._eraseAttrData()), respectProtect); this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase + y); line.isWrapped = false; } @@ -1171,16 +1171,16 @@ export class InputHandler extends Disposable implements IInputHandler { * * @vt: #Y CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Same as ED with respecting protection flag." */ - public eraseInDisplay(params: IParams, protect: boolean = false): boolean { + public eraseInDisplay(params: IParams, respectProtect: boolean = false): boolean { this._restrictCursor(this._bufferService.cols); let j; switch (params.params[0]) { case 0: j = this._activeBuffer.y; this._dirtyRowService.markDirty(j); - this._eraseInBufferLine(j++, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0, protect); + this._eraseInBufferLine(j++, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0, respectProtect); for (; j < this._bufferService.rows; j++) { - this._resetBufferLine(j, protect); + this._resetBufferLine(j, respectProtect); } this._dirtyRowService.markDirty(j); break; @@ -1188,13 +1188,13 @@ export class InputHandler extends Disposable implements IInputHandler { j = this._activeBuffer.y; this._dirtyRowService.markDirty(j); // Deleted front part of line and everything before. This line will no longer be wrapped. - this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true, protect); + this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true, respectProtect); if (this._activeBuffer.x + 1 >= this._bufferService.cols) { // Deleted entire previous line. This next line can no longer be wrapped. this._activeBuffer.lines.get(j + 1)!.isWrapped = false; } while (j--) { - this._resetBufferLine(j, protect); + this._resetBufferLine(j, respectProtect); } this._dirtyRowService.markDirty(0); break; @@ -1202,7 +1202,7 @@ export class InputHandler extends Disposable implements IInputHandler { j = this._bufferService.rows; this._dirtyRowService.markDirty(j - 1); while (j--) { - this._resetBufferLine(j, protect); + this._resetBufferLine(j, respectProtect); } this._dirtyRowService.markDirty(0); break; @@ -1243,17 +1243,17 @@ export class InputHandler extends Disposable implements IInputHandler { * * @vt: #Y CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Same as EL with respecting protecting flag." */ - public eraseInLine(params: IParams, protect: boolean = false): boolean { + public eraseInLine(params: IParams, respectProtect: boolean = false): boolean { this._restrictCursor(this._bufferService.cols); switch (params.params[0]) { case 0: - this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0, protect); + this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0, respectProtect); break; case 1: - this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1, false, protect); + this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1, false, respectProtect); break; case 2: - this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols, true, protect); + this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols, true, respectProtect); break; } this._dirtyRowService.markDirty(this._activeBuffer.y); diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index f559719e09..d44bb19772 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -204,9 +204,9 @@ export interface IBufferLine { addCodepointToCell(index: number, codePoint: number): void; insertCells(pos: number, n: number, ch: ICellData, eraseAttr?: IAttributeData): void; deleteCells(pos: number, n: number, fill: ICellData, eraseAttr?: IAttributeData): void; - replaceCells(start: number, end: number, fill: ICellData, eraseAttr?: IAttributeData, protect?: boolean): void; + replaceCells(start: number, end: number, fill: ICellData, eraseAttr?: IAttributeData, respectProtect?: boolean): void; resize(cols: number, fill: ICellData): void; - fill(fillCellData: ICellData, protect?: boolean): void; + fill(fillCellData: ICellData, respectProtect?: boolean): void; copyFrom(line: IBufferLine): void; clone(): IBufferLine; getTrimmedLength(): number; diff --git a/src/common/buffer/BufferLine.ts b/src/common/buffer/BufferLine.ts index ceb5377c78..a690c62cf0 100644 --- a/src/common/buffer/BufferLine.ts +++ b/src/common/buffer/BufferLine.ts @@ -303,9 +303,9 @@ export class BufferLine implements IBufferLine { } } - public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData, protect: boolean = false): void { - // full branching on protect==true, hopefully getting fast JIT for standard case - if (protect) { + public replaceCells(start: number, end: number, fillCellData: ICellData, eraseAttr?: IAttributeData, respectProtect: boolean = false): void { + // full branching on respectProtect==true, hopefully getting fast JIT for standard case + if (respectProtect) { if (start && this.getWidth(start - 1) === 2 && !this.isProtected(start - 1)) { this.setCellFromCodePoint(start - 1, 0, 1, eraseAttr?.fg || 0, eraseAttr?.bg || 0, eraseAttr?.extended || new ExtendedAttrs()); } @@ -374,9 +374,9 @@ export class BufferLine implements IBufferLine { } /** fill a line with fillCharData */ - public fill(fillCellData: ICellData, protect: boolean = false): void { - // full branching on protect==true, hopefully getting fast JIT for standard case - if (protect) { + public fill(fillCellData: ICellData, respectProtect: boolean = false): void { + // full branching on respectProtect==true, hopefully getting fast JIT for standard case + if (respectProtect) { for (let i = 0; i < this.length; ++i) { if (!this.isProtected(i)) { this.setCell(i, fillCellData);