Merge branch 'master' into extract_vt_features

This commit is contained in:
Jörg Breitbart
2020-01-05 21:38:21 +01:00
115 changed files with 5434 additions and 2940 deletions
+264 -121
View File
@@ -19,7 +19,7 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, Attributes, FgFlags, BgFlags, Content
import { CellData } from 'common/buffer/CellData';
import { AttributeData } from 'common/buffer/AttributeData';
import { IAttributeData, IDisposable } from 'common/Types';
import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService } from 'common/services/Services';
import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService, ICharsetService } from 'common/services/Services';
import { OscHandler } from 'common/parser/OscParser';
import { DcsHandler } from 'common/parser/DcsParser';
@@ -32,10 +32,12 @@ const GLEVEL: {[key: string]: number} = {'(': 0, ')': 1, '*': 2, '+': 3, '-': 1,
* Document common VT features here that are currently unsupported
*/
// @vt: unsupported DCS SIXEL "SIXEL Graphics" "DCS Ps ; Ps ; Ps ; q Pt ST" "Draw SIXEL image starting at cursor position."
// @vt: unsupported CSI SL "Scroll Left" "CSI Ps SP @" "Scroll viewport `Ps` times to the left."
// @vt: unsupported CSI SR "Scroll Right" "CSI Ps SP A" "Scroll viewport `Ps` times to the right."
// @vt: unsupported CSI DECIC "Insert Columns" "CSI Ps ' }" "Insert `Ps` columns at cursor position."
// @vt: unsupported CSI DECDC "Delete Columns" "CSI Ps ' ~" "Delete `Ps` columns at cursor position."
/**
* Max length of the UTF32 input buffer. Real memory consumption is 4 times higher.
*/
const MAX_PARSEBUFFER_LENGTH = 131072;
/**
* DCS subparser implementations
@@ -137,6 +139,15 @@ export class InputHandler extends Disposable implements IInputHandler {
private _utf8Decoder: Utf8ToUtf32 = new Utf8ToUtf32();
private _workCell: CellData = new CellData();
private _curAttrData: IAttributeData = DEFAULT_ATTR_DATA.clone();
private _eraseAttrDataInternal: IAttributeData = DEFAULT_ATTR_DATA.clone();
private _onRequestRefreshRows = new EventEmitter<number, number>();
public get onRequestRefreshRows(): IEvent<number, number> { return this._onRequestRefreshRows.event; }
private _onRequestReset = new EventEmitter<void>();
public get onRequestReset(): IEvent<void> { return this._onRequestReset.event; }
private _onRequestBell = new EventEmitter<void>();
public get onRequestBell(): IEvent<void> { return this._onRequestBell.event; }
private _onCursorMove = new EventEmitter<void>();
public get onCursorMove(): IEvent<void> { return this._onCursorMove.event; }
private _onLineFeed = new EventEmitter<void>();
@@ -145,8 +156,9 @@ export class InputHandler extends Disposable implements IInputHandler {
public get onScroll(): IEvent<number> { return this._onScroll.event; }
constructor(
protected _terminal: IInputHandlingTerminal,
private _terminal: IInputHandlingTerminal,
private readonly _bufferService: IBufferService,
private readonly _charsetService: ICharsetService,
private readonly _coreService: ICoreService,
private readonly _dirtyRowService: IDirtyRowService,
private readonly _logService: ILogService,
@@ -189,8 +201,12 @@ export class InputHandler extends Disposable implements IInputHandler {
* CSI handler
*/
this._parser.setCsiHandler({final: '@'}, params => this.insertChars(params));
// @vt: supported CSI SL "Scroll Left" "CSI Ps SP @" "Scroll viewport `Ps` times to the left."
this._parser.setCsiHandler({intermediates: ' ', final: '@'}, params => this.scrollLeft(params));
// @vt: supported CSI CUU "Cursor Up" "CSI Ps A" "Move cursor `Ps` times up (default=1)."
this._parser.setCsiHandler({final: 'A'}, params => this.cursorUp(params));
// @vt: supported CSI SR "Scroll Right" "CSI Ps SP A" "Scroll viewport `Ps` times to the right."
this._parser.setCsiHandler({intermediates: ' ', final: 'A'}, params => this.scrollRight(params));
// @vt: supported CSI CUD "Cursor Down" "CSI Ps B" "Move cursor `Ps` times down (default=1)."
this._parser.setCsiHandler({final: 'B'}, params => this.cursorDown(params));
// @vt: supported CSI CUF "Cursor Forward" "CSI Ps C" "Move cursor `Ps` times forward (default=1)."
@@ -321,6 +337,10 @@ export class InputHandler extends Disposable implements IInputHandler {
this._parser.setCsiHandler({final: 's'}, params => this.saveCursor(params));
// @vt: partly CSI SCORC "Restore Cursor" "CSI u" "Restore cursor position, charmap and text attributes."
this._parser.setCsiHandler({final: 'u'}, params => this.restoreCursor(params));
// @vt: supported CSI DECIC "Insert Columns" "CSI Ps ' }" "Insert `Ps` columns at cursor position."
this._parser.setCsiHandler({intermediates: '\'', final: '}'}, params => this.insertColumns(params));
// @vt: supported CSI DECDC "Delete Columns" "CSI Ps ' ~" "Delete `Ps` columns at cursor position."
this._parser.setCsiHandler({intermediates: '\'', final: '~'}, params => this.deleteColumns(params));
/**
* execute handler
@@ -426,7 +446,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._parser.setEscHandler({final: 'M'}, () => this.reverseIndex());
this._parser.setEscHandler({final: '='}, () => this.keypadApplicationMode());
this._parser.setEscHandler({final: '>'}, () => this.keypadNumericMode());
this._parser.setEscHandler({final: 'c'}, () => this.reset());
this._parser.setEscHandler({final: 'c'}, () => this.fullReset());
this._parser.setEscHandler({final: 'n'}, () => this.setgLevel(2));
this._parser.setEscHandler({final: 'o'}, () => this.setgLevel(3));
this._parser.setEscHandler({final: '|'}, () => this.setgLevel(3));
@@ -471,35 +491,60 @@ export class InputHandler extends Disposable implements IInputHandler {
this._logService.debug('parsing data', data);
// resize input buffer if needed
if (this._parseBuffer.length < data.length) {
this._parseBuffer = new Uint32Array(data.length);
if (this._parseBuffer.length < MAX_PARSEBUFFER_LENGTH) {
this._parseBuffer = new Uint32Array(Math.min(data.length, MAX_PARSEBUFFER_LENGTH));
}
}
this._parser.parse(this._parseBuffer,
(typeof data === 'string')
// Clear the dirty row service so we know which lines changed as a result of parsing
this._dirtyRowService.clearRange();
// process big data in smaller chunks
if (data.length > MAX_PARSEBUFFER_LENGTH) {
for (let i = 0; i < data.length; i += MAX_PARSEBUFFER_LENGTH) {
const end = i + MAX_PARSEBUFFER_LENGTH < data.length ? i + MAX_PARSEBUFFER_LENGTH : data.length;
const len = (typeof data === 'string')
? this._stringDecoder.decode(data.substring(i, end), this._parseBuffer)
: this._utf8Decoder.decode(data.subarray(i, end), this._parseBuffer);
this._parser.parse(this._parseBuffer, len);
}
} else {
const len = (typeof data === 'string')
? this._stringDecoder.decode(data, this._parseBuffer)
: this._utf8Decoder.decode(data, this._parseBuffer)
);
: this._utf8Decoder.decode(data, this._parseBuffer);
this._parser.parse(this._parseBuffer, len);
}
buffer = this._bufferService.buffer;
if (buffer.x !== cursorStartX || buffer.y !== cursorStartY) {
this._onCursorMove.fire();
}
this._terminal.refresh(this._dirtyRowService.start, this._dirtyRowService.end);
// Refresh any dirty rows accumulated as part of parsing
this._onRequestRefreshRows.fire(this._dirtyRowService.start, this._dirtyRowService.end);
}
public print(data: Uint32Array, start: number, end: number): void {
let code: number;
let chWidth: number;
const buffer = this._bufferService.buffer;
const charset = this._terminal.charset;
const charset = this._charsetService.charset;
const screenReaderMode = this._optionsService.options.screenReaderMode;
const cols = this._bufferService.cols;
const wraparoundMode = this._terminal.wraparoundMode;
const wraparoundMode = this._coreService.decPrivateModes.wraparound;
const insertMode = this._terminal.insertMode;
const curAttr = this._terminal.curAttrData;
const curAttr = this._curAttrData;
let bufferRow = buffer.lines.get(buffer.y + buffer.ybase);
this._dirtyRowService.markDirty(buffer.y);
// handle wide chars: reset start_cell-1 if we would overwrite the second cell of a wide char
if (buffer.x && end - start > 0 && bufferRow.getWidth(buffer.x - 1) === 2) {
bufferRow.setCellFromCodePoint(buffer.x - 1, 0, 1, curAttr.fg, curAttr.bg);
}
for (let pos = start; pos < end; ++pos) {
code = data[pos];
@@ -551,7 +596,7 @@ export class InputHandler extends Disposable implements IInputHandler {
buffer.y++;
if (buffer.y === buffer.scrollBottom + 1) {
buffer.y--;
this._terminal.scroll(true);
this._terminal.scroll(this._eraseAttrData(), true);
} else {
if (buffer.y >= this._bufferService.rows) {
buffer.y = this._bufferService.rows - 1;
@@ -575,7 +620,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// insert mode: move characters to right
if (insertMode) {
// right shift cells according to the width
bufferRow.insertCells(buffer.x, chWidth, buffer.getNullCell(curAttr));
bufferRow.insertCells(buffer.x, chWidth, buffer.getNullCell(curAttr), curAttr);
// test last cell - since the last cell has only room for
// a halfwidth char any fullwidth shifted there is lost
// and will be set to empty cell
@@ -601,7 +646,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// This needs to check whether:
// - fullwidth + surrogates: reset
// - combining: only base char gets carried on (bug in xterm?)
if (end) {
if (end - start > 0) {
bufferRow.loadCell(buffer.x - 1, this._workCell);
if (this._workCell.getWidth() === 2 || this._workCell.getCode() > 0xFFFF) {
this._parser.precedingCodepoint = 0;
@@ -611,6 +656,12 @@ export class InputHandler extends Disposable implements IInputHandler {
this._parser.precedingCodepoint = this._workCell.content;
}
}
// handle wide chars: reset cell to the right if it is second cell of a wide char
if (buffer.x < cols && end - start > 0 && bufferRow.getWidth(buffer.x) === 0 && !bufferRow.hasContent(buffer.x)) {
bufferRow.setCellFromCodePoint(buffer.x, 0, 1, curAttr.fg, curAttr.bg);
}
this._dirtyRowService.markDirty(buffer.y);
}
@@ -647,7 +698,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* Bell (Ctrl-G).
*/
public bell(): void {
this._terminal.bell();
this._onRequestBell.fire();
}
/**
@@ -658,13 +709,14 @@ export class InputHandler extends Disposable implements IInputHandler {
// make buffer local for faster access
const buffer = this._bufferService.buffer;
this._dirtyRowService.markDirty(buffer.y);
if (this._optionsService.options.convertEol) {
buffer.x = 0;
}
buffer.y++;
if (buffer.y === buffer.scrollBottom + 1) {
buffer.y--;
this._terminal.scroll();
this._terminal.scroll(this._eraseAttrData());
} else if (buffer.y >= this._bufferService.rows) {
buffer.y = this._bufferService.rows - 1;
}
@@ -672,6 +724,7 @@ export class InputHandler extends Disposable implements IInputHandler {
if (buffer.x >= this._bufferService.cols) {
buffer.x--;
}
this._dirtyRowService.markDirty(buffer.y);
this._onLineFeed.fire();
}
@@ -716,7 +769,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* G1 character set.
*/
public shiftOut(): void {
this._terminal.setgLevel(1);
this._charsetService.setgLevel(1);
}
/**
@@ -725,7 +778,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* character set (the default).
*/
public shiftIn(): void {
this._terminal.setgLevel(0);
this._charsetService.setgLevel(0);
}
/**
@@ -733,16 +786,18 @@ export class InputHandler extends Disposable implements IInputHandler {
*/
private _restrictCursor(): void {
this._bufferService.buffer.x = Math.min(this._bufferService.cols - 1, Math.max(0, this._bufferService.buffer.x));
this._bufferService.buffer.y = this._terminal.originMode
this._bufferService.buffer.y = this._coreService.decPrivateModes.origin
? Math.min(this._bufferService.buffer.scrollBottom, Math.max(this._bufferService.buffer.scrollTop, this._bufferService.buffer.y))
: Math.min(this._bufferService.rows - 1, Math.max(0, this._bufferService.buffer.y));
this._dirtyRowService.markDirty(this._bufferService.buffer.y);
}
/**
* Set absolute cursor position.
*/
private _setCursor(x: number, y: number): void {
if (this._terminal.originMode) {
this._dirtyRowService.markDirty(this._bufferService.buffer.y);
if (this._coreService.decPrivateModes.origin) {
this._bufferService.buffer.x = x;
this._bufferService.buffer.y = this._bufferService.buffer.scrollTop + y;
} else {
@@ -750,6 +805,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._bufferService.buffer.y = y;
}
this._restrictCursor();
this._dirtyRowService.markDirty(this._bufferService.buffer.y);
}
/**
@@ -952,7 +1008,8 @@ export class InputHandler extends Disposable implements IInputHandler {
line.replaceCells(
start,
end,
this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData())
this._bufferService.buffer.getNullCell(this._eraseAttrData()),
this._eraseAttrData()
);
if (clearWrap) {
line.isWrapped = false;
@@ -966,7 +1023,7 @@ export class InputHandler extends Disposable implements IInputHandler {
*/
private _resetBufferLine(y: number): void {
const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + y);
line.fill(this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData()));
line.fill(this._bufferService.buffer.getNullCell(this._eraseAttrData()));
line.isWrapped = false;
}
@@ -1081,7 +1138,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test: echo -e '\e[44m\e[1L\e[0m'
// blankLine(true) - xterm/linux behavior
buffer.lines.splice(scrollBottomAbsolute - 1, 1);
buffer.lines.splice(row, 0, buffer.getBlankLine(this._terminal.eraseAttrData()));
buffer.lines.splice(row, 0, buffer.getBlankLine(this._eraseAttrData()));
}
this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom);
@@ -1112,7 +1169,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test: echo -e '\e[44m\e[1M\e[0m'
// blankLine(true) - xterm/linux behavior
buffer.lines.splice(row, 1);
buffer.lines.splice(j, 0, buffer.getBlankLine(this._terminal.eraseAttrData()));
buffer.lines.splice(j, 0, buffer.getBlankLine(this._eraseAttrData()));
}
this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom);
@@ -1130,7 +1187,8 @@ export class InputHandler extends Disposable implements IInputHandler {
line.insertCells(
this._bufferService.buffer.x,
params.params[0] || 1,
this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData())
this._bufferService.buffer.getNullCell(this._eraseAttrData()),
this._eraseAttrData()
);
this._dirtyRowService.markDirty(this._bufferService.buffer.y);
}
@@ -1147,7 +1205,8 @@ export class InputHandler extends Disposable implements IInputHandler {
line.deleteCells(
this._bufferService.buffer.x,
params.params[0] || 1,
this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData())
this._bufferService.buffer.getNullCell(this._eraseAttrData()),
this._eraseAttrData()
);
this._dirtyRowService.markDirty(this._bufferService.buffer.y);
}
@@ -1164,7 +1223,7 @@ export class InputHandler extends Disposable implements IInputHandler {
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(this._terminal.eraseAttrData()));
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(this._eraseAttrData()));
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
}
@@ -1173,18 +1232,108 @@ export class InputHandler extends Disposable implements IInputHandler {
* CSI Ps T Scroll down Ps lines (default = 1) (SD).
*/
public scrollDown(params: IParams): void {
if (params.length < 2) {
let param = params.params[0] || 1;
let param = params.params[0] || 1;
// make buffer local for faster access
const buffer = this._bufferService.buffer;
// make buffer local for faster access
const buffer = this._bufferService.buffer;
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 0, buffer.getBlankLine(this._terminal.eraseAttrData()));
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 0, buffer.getBlankLine(DEFAULT_ATTR_DATA));
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
}
/**
* CSI Ps SP @ Scroll left Ps columns (default = 1) (SL) ECMA-48
*
* Notation: (Pn)
* Representation: CSI Pn 02/00 04/00
* Parameter default value: Pn = 1
* SL causes the data in the presentation component to be moved by n character positions
* if the line orientation is horizontal, or by n line positions if the line orientation
* is vertical, such that the data appear to move to the left; where n equals the value of Pn.
* The active presentation position is not affected by this control function.
*
* Supported:
* - always left shift (no line orientation setting respected)
*/
public scrollLeft(params: IParams): void {
const buffer = this._bufferService.buffer;
if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) {
return;
}
const param = params.params[0] || 1;
for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) {
const line = buffer.lines.get(buffer.ybase + y);
line.deleteCells(0, param, buffer.getNullCell(this._eraseAttrData()), this._eraseAttrData());
line.isWrapped = false;
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
}
/**
* CSI Ps SP A Scroll right Ps columns (default = 1) (SR) ECMA-48
*
* Notation: (Pn)
* Representation: CSI Pn 02/00 04/01
* Parameter default value: Pn = 1
* SR causes the data in the presentation component to be moved by n character positions
* if the line orientation is horizontal, or by n line positions if the line orientation
* is vertical, such that the data appear to move to the right; where n equals the value of Pn.
* The active presentation position is not affected by this control function.
*
* Supported:
* - always right shift (no line orientation setting respected)
*/
public scrollRight(params: IParams): void {
const buffer = this._bufferService.buffer;
if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) {
return;
}
const param = params.params[0] || 1;
for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) {
const line = buffer.lines.get(buffer.ybase + y);
line.insertCells(0, param, buffer.getNullCell(this._eraseAttrData()), this._eraseAttrData());
line.isWrapped = false;
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
}
/**
* CSI Pm ' }
* Insert Ps Column(s) (default = 1) (DECIC), VT420 and up.
*/
public insertColumns(params: IParams): void {
const buffer = this._bufferService.buffer;
if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) {
return;
}
const param = params.params[0] || 1;
for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) {
const line = this._bufferService.buffer.lines.get(buffer.ybase + y);
line.insertCells(buffer.x, param, buffer.getNullCell(this._eraseAttrData()), this._eraseAttrData());
line.isWrapped = false;
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
}
/**
* CSI Pm ' ~
* Delete Ps Column(s) (default = 1) (DECDC), VT420 and up.
*/
public deleteColumns(params: IParams): void {
const buffer = this._bufferService.buffer;
if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) {
return;
}
const param = params.params[0] || 1;
for (let y = buffer.scrollTop; y <= buffer.scrollBottom; ++y) {
const line = buffer.lines.get(buffer.ybase + y);
line.deleteCells(buffer.x, param, buffer.getNullCell(this._eraseAttrData()), this._eraseAttrData());
line.isWrapped = false;
}
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
}
/**
@@ -1198,7 +1347,8 @@ export class InputHandler extends Disposable implements IInputHandler {
line.replaceCells(
this._bufferService.buffer.x,
this._bufferService.buffer.x + (params.params[0] || 1),
this._bufferService.buffer.getNullCell(this._terminal.eraseAttrData())
this._bufferService.buffer.getNullCell(this._eraseAttrData()),
this._eraseAttrData()
);
this._dirtyRowService.markDirty(this._bufferService.buffer.y);
}
@@ -1411,34 +1561,32 @@ export class InputHandler extends Disposable implements IInputHandler {
this._coreService.decPrivateModes.applicationCursorKeys = true;
break;
case 2:
this._terminal.setgCharset(0, DEFAULT_CHARSET);
this._terminal.setgCharset(1, DEFAULT_CHARSET);
this._terminal.setgCharset(2, DEFAULT_CHARSET);
this._terminal.setgCharset(3, DEFAULT_CHARSET);
this._charsetService.setgCharset(0, DEFAULT_CHARSET);
this._charsetService.setgCharset(1, DEFAULT_CHARSET);
this._charsetService.setgCharset(2, DEFAULT_CHARSET);
this._charsetService.setgCharset(3, DEFAULT_CHARSET);
// set VT100 mode here
break;
case 3: // 132 col mode
// TODO: move DECCOLM into compat addon
this._terminal.savedCols = this._bufferService.cols;
this._terminal.resize(132, this._bufferService.rows);
this._terminal.reset();
this._onRequestReset.fire();
break;
case 6:
this._terminal.originMode = true;
this._coreService.decPrivateModes.origin = true;
this._setCursor(0, 0);
break;
case 7:
this._terminal.wraparoundMode = true;
this._coreService.decPrivateModes.wraparound = true;
break;
case 12:
// this.cursorBlink = true;
break;
case 66:
this._logService.debug('Serial port requested application keypad.');
this._terminal.applicationKeypad = true;
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._coreService.decPrivateModes.applicationKeypad = true;
this._terminal.viewport?.syncScrollArea();
break;
case 9: // X10 Mouse
// no release, no motion, no wheel, no modifiers.
@@ -1461,19 +1609,17 @@ export class InputHandler extends Disposable implements IInputHandler {
// focusout: ^[[O
this._terminal.sendFocus = true;
break;
case 1005: // utf8 ext mode mouse
// for wide terminals
// simply encodes large values as utf8 characters
this._coreMouseService.activeEncoding = 'UTF8';
case 1005: // utf8 ext mode mouse - removed in #2507
this._logService.debug('DECSET 1005 not supported (see #2507)');
break;
case 1006: // sgr ext mode mouse
this._coreMouseService.activeEncoding = 'SGR';
break;
case 1015: // urxvt ext mode mouse
this._coreMouseService.activeEncoding = 'URXVT';
case 1015: // urxvt ext mode mouse - removed in #2507
this._logService.debug('DECSET 1015 not supported (see #2507)');
break;
case 25: // show cursor
this._terminal.cursorHidden = false;
this._coreService.isCursorHidden = false;
break;
case 1048: // alt screen cursor
this.saveCursor();
@@ -1483,11 +1629,9 @@ export class InputHandler extends Disposable implements IInputHandler {
// FALL-THROUGH
case 47: // alt screen buffer
case 1047: // alt screen buffer
this._bufferService.buffers.activateAltBuffer(this._terminal.eraseAttrData());
this._terminal.refresh(0, this._bufferService.rows - 1);
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._bufferService.buffers.activateAltBuffer(this._eraseAttrData());
this._onRequestRefreshRows.fire(0, this._bufferService.rows - 1);
this._terminal.viewport?.syncScrollArea();
this._terminal.showCursor();
break;
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
@@ -1606,24 +1750,22 @@ export class InputHandler extends Disposable implements IInputHandler {
this._terminal.resize(this._terminal.savedCols, this._bufferService.rows);
}
delete this._terminal.savedCols;
this._terminal.reset();
this._onRequestReset.fire();
break;
case 6:
this._terminal.originMode = false;
this._coreService.decPrivateModes.origin = false;
this._setCursor(0, 0);
break;
case 7:
this._terminal.wraparoundMode = false;
this._coreService.decPrivateModes.wraparound = false;
break;
case 12:
// this.cursorBlink = false;
break;
case 66:
this._logService.debug('Switching back to normal keypad.');
this._terminal.applicationKeypad = false;
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._coreService.decPrivateModes.applicationKeypad = false;
this._terminal.viewport?.syncScrollArea();
break;
case 9: // X10 Mouse
case 1000: // vt200 mouse
@@ -1634,17 +1776,17 @@ export class InputHandler extends Disposable implements IInputHandler {
case 1004: // send focusin/focusout events
this._terminal.sendFocus = false;
break;
case 1005: // utf8 ext mode mouse
this._coreMouseService.activeEncoding = 'DEFAULT';
case 1005: // utf8 ext mode mouse - removed in #2507
this._logService.debug('DECRST 1005 not supported (see #2507)');
break;
case 1006: // sgr ext mode mouse
this._coreMouseService.activeEncoding = 'DEFAULT';
break;
case 1015: // urxvt ext mode mouse
this._coreMouseService.activeEncoding = 'DEFAULT';
case 1015: // urxvt ext mode mouse - removed in #2507
this._logService.debug('DECRST 1015 not supported (see #2507)');
break;
case 25: // hide cursor
this._terminal.cursorHidden = true;
this._coreService.isCursorHidden = true;
break;
case 1048: // alt screen cursor
this.restoreCursor();
@@ -1658,10 +1800,8 @@ export class InputHandler extends Disposable implements IInputHandler {
if (params.params[i] === 1049) {
this.restoreCursor();
}
this._terminal.refresh(0, this._bufferService.rows - 1);
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._onRequestRefreshRows.fire(0, this._bufferService.rows - 1);
this._terminal.viewport?.syncScrollArea();
this._terminal.showCursor();
break;
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
@@ -1811,14 +1951,14 @@ export class InputHandler extends Disposable implements IInputHandler {
public charAttributes(params: IParams): void {
// Optimize a single SGR0.
if (params.length === 1 && params.params[0] === 0) {
this._terminal.curAttrData.fg = DEFAULT_ATTR_DATA.fg;
this._terminal.curAttrData.bg = DEFAULT_ATTR_DATA.bg;
this._curAttrData.fg = DEFAULT_ATTR_DATA.fg;
this._curAttrData.bg = DEFAULT_ATTR_DATA.bg;
return;
}
const l = params.length;
let p;
const attr = this._terminal.curAttrData;
const attr = this._curAttrData;
for (let i = 0; i < l; i++) {
p = params.params[i];
@@ -1978,22 +2118,15 @@ export class InputHandler extends Disposable implements IInputHandler {
* http://vt100.net/docs/vt220-rm/table4-10.html
*/
public softReset(params: IParams): void {
this._terminal.cursorHidden = false;
this._coreService.isCursorHidden = false;
this._terminal.insertMode = false;
this._terminal.originMode = false;
this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false
this._terminal.applicationKeypad = false; // ?
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._coreService.decPrivateModes.applicationCursorKeys = false;
this._terminal.viewport?.syncScrollArea();
this._bufferService.buffer.scrollTop = 0;
this._bufferService.buffer.scrollBottom = this._bufferService.rows - 1;
this._terminal.curAttrData = DEFAULT_ATTR_DATA.clone();
this._curAttrData = DEFAULT_ATTR_DATA.clone();
this._bufferService.buffer.x = this._bufferService.buffer.y = 0; // ?
this._terminal.charset = null;
this._terminal.glevel = 0; // ??
this._terminal.charsets = [null]; // ??
this._coreService.reset();
this._charsetService.reset();
}
/**
@@ -2055,9 +2188,9 @@ export class InputHandler extends Disposable implements IInputHandler {
public saveCursor(params?: IParams): void {
this._bufferService.buffer.savedX = this._bufferService.buffer.x;
this._bufferService.buffer.savedY = this._bufferService.buffer.ybase + this._bufferService.buffer.y;
this._bufferService.buffer.savedCurAttrData.fg = this._terminal.curAttrData.fg;
this._bufferService.buffer.savedCurAttrData.bg = this._terminal.curAttrData.bg;
this._bufferService.buffer.savedCharset = this._terminal.charset;
this._bufferService.buffer.savedCurAttrData.fg = this._curAttrData.fg;
this._bufferService.buffer.savedCurAttrData.bg = this._curAttrData.bg;
this._bufferService.buffer.savedCharset = this._charsetService.charset;
}
@@ -2069,11 +2202,11 @@ export class InputHandler extends Disposable implements IInputHandler {
public restoreCursor(params?: IParams): void {
this._bufferService.buffer.x = this._bufferService.buffer.savedX || 0;
this._bufferService.buffer.y = Math.max(this._bufferService.buffer.savedY - this._bufferService.buffer.ybase, 0);
this._terminal.curAttrData.fg = this._bufferService.buffer.savedCurAttrData.fg;
this._terminal.curAttrData.bg = this._bufferService.buffer.savedCurAttrData.bg;
this._terminal.charset = (this as any)._savedCharset;
this._curAttrData.fg = this._bufferService.buffer.savedCurAttrData.fg;
this._curAttrData.bg = this._bufferService.buffer.savedCurAttrData.bg;
this._charsetService.charset = (this as any)._savedCharset;
if (this._bufferService.buffer.savedCharset) {
this._terminal.charset = this._bufferService.buffer.savedCharset;
this._charsetService.charset = this._bufferService.buffer.savedCharset;
}
this._restrictCursor();
}
@@ -2106,10 +2239,8 @@ export class InputHandler extends Disposable implements IInputHandler {
*/
public keypadApplicationMode(): void {
this._logService.debug('Serial port requested application keypad.');
this._terminal.applicationKeypad = true;
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._coreService.decPrivateModes.applicationKeypad = true;
this._terminal.viewport?.syncScrollArea();
}
/**
@@ -2119,10 +2250,8 @@ export class InputHandler extends Disposable implements IInputHandler {
*/
public keypadNumericMode(): void {
this._logService.debug('Switching back to normal keypad.');
this._terminal.applicationKeypad = false;
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._coreService.decPrivateModes.applicationKeypad = false;
this._terminal.viewport?.syncScrollArea();
}
/**
@@ -2132,8 +2261,8 @@ export class InputHandler extends Disposable implements IInputHandler {
* therefore ESC % G does the same.
*/
public selectDefaultCharset(): void {
this._terminal.setgLevel(0);
this._terminal.setgCharset(0, DEFAULT_CHARSET); // US (default)
this._charsetService.setgLevel(0);
this._charsetService.setgCharset(0, DEFAULT_CHARSET); // US (default)
}
/**
@@ -2160,7 +2289,7 @@ export class InputHandler extends Disposable implements IInputHandler {
if (collectAndFlag[0] === '/') {
return; // TODO: Is this supported?
}
this._terminal.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] || DEFAULT_CHARSET);
this._charsetService.setgCharset(GLEVEL[collectAndFlag[0]], CHARSETS[collectAndFlag[1]] || DEFAULT_CHARSET);
return;
}
@@ -2176,7 +2305,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._bufferService.buffer.y++;
if (buffer.y === buffer.scrollBottom + 1) {
buffer.y--;
this._terminal.scroll();
this._terminal.scroll(this._eraseAttrData());
} else if (buffer.y >= this._bufferService.rows) {
buffer.y = this._bufferService.rows - 1;
}
@@ -2210,7 +2339,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// blankLine(true) is xterm/linux behavior
const scrollRegionHeight = buffer.scrollBottom - buffer.scrollTop;
buffer.lines.shiftElements(buffer.y + buffer.ybase, scrollRegionHeight, 1);
buffer.lines.set(buffer.y + buffer.ybase, buffer.getBlankLine(this._terminal.eraseAttrData()));
buffer.lines.set(buffer.y + buffer.ybase, buffer.getBlankLine(this._eraseAttrData()));
this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom);
} else {
buffer.y--;
@@ -2223,9 +2352,23 @@ export class InputHandler extends Disposable implements IInputHandler {
* DEC mnemonic: RIS (https://vt100.net/docs/vt510-rm/RIS.html)
* Reset to initial state.
*/
public reset(): void {
public fullReset(): void {
this._parser.reset();
this._terminal.reset(); // TODO: save to move from terminal?
this._onRequestReset.fire();
}
public reset(): void {
this._curAttrData = DEFAULT_ATTR_DATA.clone();
this._eraseAttrDataInternal = DEFAULT_ATTR_DATA.clone();
}
/**
* back_color_erase feature for xterm.
*/
private _eraseAttrData(): IAttributeData {
this._eraseAttrDataInternal.bg &= ~(Attributes.CM_MASK | 0xFFFFFF);
this._eraseAttrDataInternal.bg |= this._curAttrData.bg & ~0xFC000000;
return this._eraseAttrDataInternal;
}
/**
@@ -2239,7 +2382,7 @@ export class InputHandler extends Disposable implements IInputHandler {
* you use another locking shift. (partly supported)
*/
public setgLevel(level: number): void {
this._terminal.setgLevel(level); // TODO: save to move from terminal?
this._charsetService.setgLevel(level);
}
/**
@@ -2254,8 +2397,8 @@ export class InputHandler extends Disposable implements IInputHandler {
// prepare cell data
const cell = new CellData();
cell.content = 1 << Content.WIDTH_SHIFT | 'E'.charCodeAt(0);
cell.fg = this._terminal.curAttrData.fg;
cell.bg = this._terminal.curAttrData.bg;
cell.fg = this._curAttrData.fg;
cell.bg = this._curAttrData.bg;
const buffer = this._bufferService.buffer;