diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 9ce14daf..3c9bea4c 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -8,6 +8,8 @@ import { addDisposableDomListener } from 'browser/Lifecycle'; import { IColorSet, IViewport } from 'browser/Types'; import { ICharSizeService, IRenderService } from 'browser/services/Services'; import { IBufferService, IOptionsService } from 'common/services/Services'; +import { IBuffer } from 'common/buffer/Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; const FALLBACK_SCROLL_BAR_WIDTH = 15; @@ -18,12 +20,15 @@ const FALLBACK_SCROLL_BAR_WIDTH = 15; export class Viewport extends Disposable implements IViewport { public scrollBarWidth: number = 0; private _currentRowHeight: number = 0; + private _currentScaledCellHeight: number = 0; private _lastRecordedBufferLength: number = 0; private _lastRecordedViewportHeight: number = 0; private _lastRecordedBufferHeight: number = 0; private _lastTouchY: number = 0; private _lastScrollTop: number = 0; private _lastHadScrollBar: boolean = false; + private _activeBuffer: IBuffer; + private _renderDimensions: IRenderDimensions; // Stores a partial line amount when scrolling, this is used to keep track of how much of a line // is scrolled so we can "scroll" over partial lines and feel natural on touchpads. This is a @@ -51,6 +56,12 @@ export class Viewport extends Disposable implements IViewport { this._lastHadScrollBar = true; this.register(addDisposableDomListener(this._viewportElement, 'scroll', this._onScroll.bind(this))); + // Track properties used in performance critical code manually to avoid using slow getters + this._activeBuffer = this._bufferService.buffer; + this.register(this._bufferService.buffers.onBufferActivate(e => this._activeBuffer = e.activeBuffer)); + this._renderDimensions = this._renderService.dimensions; + this.register(this._renderService.onDimensionsChange(e => this._renderDimensions = e)); + // Perform this async to ensure the ICharSizeService is ready. setTimeout(() => this.syncScrollArea(), 0); } @@ -79,6 +90,7 @@ export class Viewport extends Disposable implements IViewport { private _innerRefresh(): void { if (this._charSizeService.height > 0) { this._currentRowHeight = this._renderService.dimensions.scaledCellHeight / window.devicePixelRatio; + this._currentScaledCellHeight = this._renderService.dimensions.scaledCellHeight; this._lastRecordedViewportHeight = this._viewportElement.offsetHeight; const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._renderService.dimensions.canvasHeight); if (this._lastRecordedBufferHeight !== newBufferHeight) { @@ -126,20 +138,13 @@ export class Viewport extends Disposable implements IViewport { } // If the buffer position doesn't match last scroll top - const newScrollTop = this._bufferService.buffer.ydisp * this._currentRowHeight; - if (this._lastScrollTop !== newScrollTop) { - this._refresh(immediate); - return; - } - - // If element's scroll top changed, this can happen when hiding the element - if (this._lastScrollTop !== this._viewportElement.scrollTop) { + if (this._lastScrollTop !== this._activeBuffer.ydisp * this._currentRowHeight) { this._refresh(immediate); return; } // If row height changed - if (this._renderService.dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) { + if (this._renderDimensions.scaledCellHeight !== this._currentScaledCellHeight) { this._refresh(immediate); return; } diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index d4354e90..f2f0d0ce 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -20,6 +20,7 @@ import { AttributeData } from 'common/buffer/AttributeData'; import { ICoreService, IBufferService, IOptionsService, ILogService, IDirtyRowService, ICoreMouseService, ICharsetService, IUnicodeService, LogLevelEnum } from 'common/services/Services'; import { OscHandler } from 'common/parser/OscParser'; import { DcsHandler } from 'common/parser/DcsParser'; +import { IBuffer } from 'common/buffer/Types'; /** * Map collect to glevel. Used in `selectCharset`. @@ -234,6 +235,8 @@ export class InputHandler extends Disposable implements IInputHandler { private _curAttrData: IAttributeData = DEFAULT_ATTR_DATA.clone(); private _eraseAttrDataInternal: IAttributeData = DEFAULT_ATTR_DATA.clone(); + private _activeBuffer: IBuffer; + private _onRequestBell = new EventEmitter(); public get onRequestBell(): IEvent { return this._onRequestBell.event; } private _onRequestRefreshRows = new EventEmitter(); @@ -282,6 +285,10 @@ export class InputHandler extends Disposable implements IInputHandler { super(); this.register(this._parser); + // Track properties used in performance critical code manually to avoid using slow getters + this._activeBuffer = this._bufferService.buffer; + this.register(this._bufferService.buffers.onBufferActivate(e => this._activeBuffer = e.activeBuffer)); + /** * custom fallback handlers */ @@ -508,9 +515,8 @@ export class InputHandler extends Disposable implements IInputHandler { */ public parse(data: string | Uint8Array, promiseResult?: boolean): void | Promise { let result: void | Promise; - let buffer = this._bufferService.buffer; - let cursorStartX = buffer.x; - let cursorStartY = buffer.y; + let cursorStartX = this._activeBuffer.x; + let cursorStartY = this._activeBuffer.y; let start = 0; const wasPaused = this._parseStack.paused; @@ -569,8 +575,7 @@ export class InputHandler extends Disposable implements IInputHandler { } } - buffer = this._bufferService.buffer; - if (buffer.x !== cursorStartX || buffer.y !== cursorStartY) { + if (this._activeBuffer.x !== cursorStartX || this._activeBuffer.y !== cursorStartY) { this._onCursorMove.fire(); } @@ -581,20 +586,19 @@ export class InputHandler extends Disposable implements IInputHandler { public print(data: Uint32Array, start: number, end: number): void { let code: number; let chWidth: number; - const buffer = this._bufferService.buffer; const charset = this._charsetService.charset; const screenReaderMode = this._optionsService.options.screenReaderMode; const cols = this._bufferService.cols; const wraparoundMode = this._coreService.decPrivateModes.wraparound; const insertMode = this._coreService.modes.insertMode; const curAttr = this._curAttrData; - let bufferRow = buffer.lines.get(buffer.ybase + buffer.y)!; + let bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; - this._dirtyRowService.markDirty(buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.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, curAttr.extended); + if (this._activeBuffer.x && end - start > 0 && bufferRow.getWidth(this._activeBuffer.x - 1) === 2) { + bufferRow.setCellFromCodePoint(this._activeBuffer.x - 1, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); } for (let pos = start; pos < end; ++pos) { @@ -619,17 +623,17 @@ export class InputHandler extends Disposable implements IInputHandler { } // insert combining char at last cursor position - // buffer.x should never be 0 for a combining char + // this._activeBuffer.x should never be 0 for a combining char // since they always follow a cell consuming char - // therefore we can test for buffer.x to avoid overflow left - if (!chWidth && buffer.x) { - if (!bufferRow.getWidth(buffer.x - 1)) { + // therefore we can test for this._activeBuffer.x to avoid overflow left + if (!chWidth && this._activeBuffer.x) { + if (!bufferRow.getWidth(this._activeBuffer.x - 1)) { // found empty cell after fullwidth, need to go 2 cells back // it is save to step 2 cells back here // since an empty cell is only set by fullwidth chars - bufferRow.addCodepointToCell(buffer.x - 2, code); + bufferRow.addCodepointToCell(this._activeBuffer.x - 2, code); } else { - bufferRow.addCodepointToCell(buffer.x - 1, code); + bufferRow.addCodepointToCell(this._activeBuffer.x - 1, code); } continue; } @@ -637,31 +641,31 @@ export class InputHandler extends Disposable implements IInputHandler { // goto next line if ch would overflow // NOTE: To avoid costly width checks here, // the terminal does not allow a cols < 2. - if (buffer.x + chWidth - 1 >= cols) { + if (this._activeBuffer.x + chWidth - 1 >= cols) { // autowrap - DECAWM // automatically wraps to the beginning of the next line if (wraparoundMode) { // clear left over cells to the right - while (buffer.x < cols) { - bufferRow.setCellFromCodePoint(buffer.x++, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); + while (this._activeBuffer.x < cols) { + bufferRow.setCellFromCodePoint(this._activeBuffer.x++, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); } - buffer.x = 0; - buffer.y++; - if (buffer.y === buffer.scrollBottom + 1) { - buffer.y--; + this._activeBuffer.x = 0; + this._activeBuffer.y++; + if (this._activeBuffer.y === this._activeBuffer.scrollBottom + 1) { + this._activeBuffer.y--; this._bufferService.scroll(this._eraseAttrData(), true); } else { - if (buffer.y >= this._bufferService.rows) { - buffer.y = this._bufferService.rows - 1; + if (this._activeBuffer.y >= this._bufferService.rows) { + this._activeBuffer.y = this._bufferService.rows - 1; } // The line already exists (eg. the initial viewport), mark it as a // wrapped line - buffer.lines.get(buffer.ybase + buffer.y)!.isWrapped = true; + this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = true; } // row changed, get it again - bufferRow = buffer.lines.get(buffer.ybase + buffer.y)!; + bufferRow = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; } else { - buffer.x = cols - 1; + this._activeBuffer.x = cols - 1; if (chWidth === 2) { // FIXME: check for xterm behavior // What to do here? We got a wide char that does not fit into last cell @@ -673,7 +677,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), curAttr); + bufferRow.insertCells(this._activeBuffer.x, chWidth, this._activeBuffer.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 @@ -683,15 +687,15 @@ export class InputHandler extends Disposable implements IInputHandler { } // write current char to buffer and advance cursor - bufferRow.setCellFromCodePoint(buffer.x++, code, chWidth, curAttr.fg, curAttr.bg, curAttr.extended); + bufferRow.setCellFromCodePoint(this._activeBuffer.x++, code, chWidth, curAttr.fg, curAttr.bg, curAttr.extended); // fullwidth char - also set next cell to placeholder stub and advance cursor // for graphemes bigger than fullwidth we can simply loop to zero - // we already made sure above, that buffer.x + chWidth will not overflow right + // we already made sure above, that this._activeBuffer.x + chWidth will not overflow right if (chWidth > 0) { while (--chWidth) { // other than a regular empty cell a cell following a wide char has no width - bufferRow.setCellFromCodePoint(buffer.x++, 0, 0, curAttr.fg, curAttr.bg, curAttr.extended); + bufferRow.setCellFromCodePoint(this._activeBuffer.x++, 0, 0, curAttr.fg, curAttr.bg, curAttr.extended); } } } @@ -700,7 +704,7 @@ export class InputHandler extends Disposable implements IInputHandler { // - fullwidth + surrogates: reset // - combining: only base char gets carried on (bug in xterm?) if (end - start > 0) { - bufferRow.loadCell(buffer.x - 1, this._workCell); + bufferRow.loadCell(this._activeBuffer.x - 1, this._workCell); if (this._workCell.getWidth() === 2 || this._workCell.getCode() > 0xFFFF) { this._parser.precedingCodepoint = 0; } else if (this._workCell.isCombined()) { @@ -711,11 +715,11 @@ export class InputHandler extends Disposable implements IInputHandler { } // 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, curAttr.extended); + if (this._activeBuffer.x < cols && end - start > 0 && bufferRow.getWidth(this._activeBuffer.x) === 0 && !bufferRow.hasContent(this._activeBuffer.x)) { + bufferRow.setCellFromCodePoint(this._activeBuffer.x, 0, 1, curAttr.fg, curAttr.bg, curAttr.extended); } - this._dirtyRowService.markDirty(buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); } /** @@ -779,25 +783,22 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y C0 FF "Form Feed" "\f, \x0C" "Treated as LF." */ public lineFeed(): boolean { - // make buffer local for faster access - const buffer = this._bufferService.buffer; - - this._dirtyRowService.markDirty(buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); if (this._optionsService.options.convertEol) { - buffer.x = 0; + this._activeBuffer.x = 0; } - buffer.y++; - if (buffer.y === buffer.scrollBottom + 1) { - buffer.y--; + this._activeBuffer.y++; + if (this._activeBuffer.y === this._activeBuffer.scrollBottom + 1) { + this._activeBuffer.y--; this._bufferService.scroll(this._eraseAttrData()); - } else if (buffer.y >= this._bufferService.rows) { - buffer.y = this._bufferService.rows - 1; + } else if (this._activeBuffer.y >= this._bufferService.rows) { + this._activeBuffer.y = this._bufferService.rows - 1; } // If the end of the line is hit, prevent this action from wrapping around to the next line. - if (buffer.x >= this._bufferService.cols) { - buffer.x--; + if (this._activeBuffer.x >= this._bufferService.cols) { + this._activeBuffer.x--; } - this._dirtyRowService.markDirty(buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); this._onLineFeed.fire(); return true; @@ -810,7 +811,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y C0 CR "Carriage Return" "\r, \x0D" "Move the cursor to the beginning of the row." */ public carriageReturn(): boolean { - this._bufferService.buffer.x = 0; + this._activeBuffer.x = 0; return true; } @@ -826,13 +827,11 @@ export class InputHandler extends Disposable implements IInputHandler { * with the cursor, thus at the home position (top-leftmost cell) this has no effect. */ public backspace(): boolean { - const buffer = this._bufferService.buffer; - // reverse wrap-around is disabled if (!this._coreService.decPrivateModes.reverseWraparound) { this._restrictCursor(); - if (buffer.x > 0) { - buffer.x--; + if (this._activeBuffer.x > 0) { + this._activeBuffer.x--; } return true; } @@ -842,8 +841,8 @@ export class InputHandler extends Disposable implements IInputHandler { // to be at x=cols to be able to address the last cell of a row by BS this._restrictCursor(this._bufferService.cols); - if (buffer.x > 0) { - buffer.x--; + if (this._activeBuffer.x > 0) { + this._activeBuffer.x--; } else { /** * reverse wrap-around handling: @@ -853,21 +852,21 @@ export class InputHandler extends Disposable implements IInputHandler { * - cannot peek into scrollbuffer * - any cursor movement sequence keeps working as expected */ - if (buffer.x === 0 - && buffer.y > buffer.scrollTop - && buffer.y <= buffer.scrollBottom - && buffer.lines.get(buffer.ybase + buffer.y)?.isWrapped) + if (this._activeBuffer.x === 0 + && this._activeBuffer.y > this._activeBuffer.scrollTop + && this._activeBuffer.y <= this._activeBuffer.scrollBottom + && this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)?.isWrapped) { - buffer.lines.get(buffer.ybase + buffer.y)!.isWrapped = false; - buffer.y--; - buffer.x = this._bufferService.cols - 1; + this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!.isWrapped = false; + this._activeBuffer.y--; + this._activeBuffer.x = this._bufferService.cols - 1; // find last taken cell - last cell can have 3 different states: // - hasContent(true) + hasWidth(1): narrow char - we are done // - hasWidth(0): second part of wide char - we are done // - hasContent(false) + hasWidth(1): empty cell due to early wrapping wide char, go one cell further back - const line = buffer.lines.get(buffer.ybase + buffer.y)!; - if (line.hasWidth(buffer.x) && !line.hasContent(buffer.x)) { - buffer.x--; + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y)!; + if (line.hasWidth(this._activeBuffer.x) && !line.hasContent(this._activeBuffer.x)) { + this._activeBuffer.x--; // We do this only once, since width=1 + hasContent=false currently happens only once before // early wrapping of a wide char. // This needs to be fixed once we support graphemes taking more than 2 cells. @@ -885,13 +884,13 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y C0 HT "Horizontal Tabulation" "\t, \x09" "Move the cursor to the next character tab stop." */ public tab(): boolean { - if (this._bufferService.buffer.x >= this._bufferService.cols) { + if (this._activeBuffer.x >= this._bufferService.cols) { return true; } - const originalX = this._bufferService.buffer.x; - this._bufferService.buffer.x = this._bufferService.buffer.nextStop(); + const originalX = this._activeBuffer.x; + this._activeBuffer.x = this._activeBuffer.nextStop(); if (this._optionsService.options.screenReaderMode) { - this._onA11yTab.fire(this._bufferService.buffer.x - originalX); + this._onA11yTab.fire(this._activeBuffer.x - originalX); } return true; } @@ -924,27 +923,27 @@ export class InputHandler extends Disposable implements IInputHandler { * Restrict cursor to viewport size / scroll margin (origin mode). */ private _restrictCursor(maxCol: number = this._bufferService.cols - 1): void { - this._bufferService.buffer.x = Math.min(maxCol, Math.max(0, this._bufferService.buffer.x)); - 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); + this._activeBuffer.x = Math.min(maxCol, Math.max(0, this._activeBuffer.x)); + this._activeBuffer.y = this._coreService.decPrivateModes.origin + ? Math.min(this._activeBuffer.scrollBottom, Math.max(this._activeBuffer.scrollTop, this._activeBuffer.y)) + : Math.min(this._bufferService.rows - 1, Math.max(0, this._activeBuffer.y)); + this._dirtyRowService.markDirty(this._activeBuffer.y); } /** * Set absolute cursor position. */ private _setCursor(x: number, y: number): void { - this._dirtyRowService.markDirty(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); if (this._coreService.decPrivateModes.origin) { - this._bufferService.buffer.x = x; - this._bufferService.buffer.y = this._bufferService.buffer.scrollTop + y; + this._activeBuffer.x = x; + this._activeBuffer.y = this._activeBuffer.scrollTop + y; } else { - this._bufferService.buffer.x = x; - this._bufferService.buffer.y = y; + this._activeBuffer.x = x; + this._activeBuffer.y = y; } this._restrictCursor(); - this._dirtyRowService.markDirty(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); } /** @@ -954,7 +953,7 @@ export class InputHandler extends Disposable implements IInputHandler { // for relative changes we have to make sure we are within 0 .. cols/rows - 1 // before calculating the new position this._restrictCursor(); - this._setCursor(this._bufferService.buffer.x + x, this._bufferService.buffer.y + y); + this._setCursor(this._activeBuffer.x + x, this._activeBuffer.y + y); } /** @@ -966,7 +965,7 @@ export class InputHandler extends Disposable implements IInputHandler { */ public cursorUp(params: IParams): boolean { // stop at scrollTop - const diffToTop = this._bufferService.buffer.y - this._bufferService.buffer.scrollTop; + const diffToTop = this._activeBuffer.y - this._activeBuffer.scrollTop; if (diffToTop >= 0) { this._moveCursor(0, -Math.min(diffToTop, params.params[0] || 1)); } else { @@ -984,7 +983,7 @@ export class InputHandler extends Disposable implements IInputHandler { */ public cursorDown(params: IParams): boolean { // stop at scrollBottom - const diffToBottom = this._bufferService.buffer.scrollBottom - this._bufferService.buffer.y; + const diffToBottom = this._activeBuffer.scrollBottom - this._activeBuffer.y; if (diffToBottom >= 0) { this._moveCursor(0, Math.min(diffToBottom, params.params[0] || 1)); } else { @@ -1025,7 +1024,7 @@ export class InputHandler extends Disposable implements IInputHandler { */ public cursorNextLine(params: IParams): boolean { this.cursorDown(params); - this._bufferService.buffer.x = 0; + this._activeBuffer.x = 0; return true; } @@ -1039,7 +1038,7 @@ export class InputHandler extends Disposable implements IInputHandler { */ public cursorPrecedingLine(params: IParams): boolean { this.cursorUp(params); - this._bufferService.buffer.x = 0; + this._activeBuffer.x = 0; return true; } @@ -1050,7 +1049,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y CSI CHA "Cursor Horizontal Absolute" "CSI Ps G" "Move cursor to `Ps`-th column of the active row (default=1)." */ public cursorCharAbsolute(params: IParams): boolean { - this._setCursor((params.params[0] || 1) - 1, this._bufferService.buffer.y); + this._setCursor((params.params[0] || 1) - 1, this._activeBuffer.y); return true; } @@ -1081,7 +1080,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y CSI HPA "Horizontal Position Absolute" "CSI Ps ` " "Same as CHA." */ public charPosAbsolute(params: IParams): boolean { - this._setCursor((params.params[0] || 1) - 1, this._bufferService.buffer.y); + this._setCursor((params.params[0] || 1) - 1, this._activeBuffer.y); return true; } @@ -1103,7 +1102,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y CSI VPA "Vertical Position Absolute" "CSI Ps d" "Move cursor to `Ps`-th row (default=1)." */ public linePosAbsolute(params: IParams): boolean { - this._setCursor(this._bufferService.buffer.x, (params.params[0] || 1) - 1); + this._setCursor(this._activeBuffer.x, (params.params[0] || 1) - 1); return true; } @@ -1146,9 +1145,9 @@ export class InputHandler extends Disposable implements IInputHandler { public tabClear(params: IParams): boolean { const param = params.params[0]; if (param === 0) { - delete this._bufferService.buffer.tabs[this._bufferService.buffer.x]; + delete this._activeBuffer.tabs[this._activeBuffer.x]; } else if (param === 3) { - this._bufferService.buffer.tabs = {}; + this._activeBuffer.tabs = {}; } return true; } @@ -1160,12 +1159,12 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y CSI CHT "Cursor Horizontal Tabulation" "CSI Ps I" "Move cursor `Ps` times tabs forward (default=1)." */ public cursorForwardTab(params: IParams): boolean { - if (this._bufferService.buffer.x >= this._bufferService.cols) { + if (this._activeBuffer.x >= this._bufferService.cols) { return true; } let param = params.params[0] || 1; while (param--) { - this._bufferService.buffer.x = this._bufferService.buffer.nextStop(); + this._activeBuffer.x = this._activeBuffer.nextStop(); } return true; } @@ -1176,16 +1175,13 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y CSI CBT "Cursor Backward Tabulation" "CSI Ps Z" "Move cursor `Ps` tabs backward (default=1)." */ public cursorBackwardTab(params: IParams): boolean { - if (this._bufferService.buffer.x >= this._bufferService.cols) { + if (this._activeBuffer.x >= this._bufferService.cols) { return true; } let param = params.params[0] || 1; - // make buffer local for faster access - const buffer = this._bufferService.buffer; - while (param--) { - buffer.x = buffer.prevStop(); + this._activeBuffer.x = this._activeBuffer.prevStop(); } return true; } @@ -1199,11 +1195,11 @@ export class InputHandler extends Disposable implements IInputHandler { * @param end end - 1 is last erased cell */ private _eraseInBufferLine(y: number, start: number, end: number, clearWrap: boolean = false): void { - const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + y)!; + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; line.replaceCells( start, end, - this._bufferService.buffer.getNullCell(this._eraseAttrData()), + this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData() ); if (clearWrap) { @@ -1217,8 +1213,8 @@ export class InputHandler extends Disposable implements IInputHandler { * @param y row index */ private _resetBufferLine(y: number): void { - const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + y)!; - line.fill(this._bufferService.buffer.getNullCell(this._eraseAttrData())); + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; + line.fill(this._activeBuffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; } @@ -1251,22 +1247,22 @@ export class InputHandler extends Disposable implements IInputHandler { let j; switch (params.params[0]) { case 0: - j = this._bufferService.buffer.y; + j = this._activeBuffer.y; this._dirtyRowService.markDirty(j); - this._eraseInBufferLine(j++, this._bufferService.buffer.x, this._bufferService.cols, this._bufferService.buffer.x === 0); + this._eraseInBufferLine(j++, this._activeBuffer.x, this._bufferService.cols, this._activeBuffer.x === 0); for (; j < this._bufferService.rows; j++) { this._resetBufferLine(j); } this._dirtyRowService.markDirty(j); break; case 1: - j = this._bufferService.buffer.y; + 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._bufferService.buffer.x + 1, true); - if (this._bufferService.buffer.x + 1 >= this._bufferService.cols) { + this._eraseInBufferLine(j, 0, this._activeBuffer.x + 1, true); + if (this._activeBuffer.x + 1 >= this._bufferService.cols) { // Deleted entire previous line. This next line can no longer be wrapped. - this._bufferService.buffer.lines.get(j + 1)!.isWrapped = false; + this._activeBuffer.lines.get(j + 1)!.isWrapped = false; } while (j--) { this._resetBufferLine(j); @@ -1283,11 +1279,11 @@ export class InputHandler extends Disposable implements IInputHandler { break; case 3: // Clear scrollback (everything not in viewport) - const scrollBackSize = this._bufferService.buffer.lines.length - this._bufferService.rows; + const scrollBackSize = this._activeBuffer.lines.length - this._bufferService.rows; if (scrollBackSize > 0) { - this._bufferService.buffer.lines.trimStart(scrollBackSize); - this._bufferService.buffer.ybase = Math.max(this._bufferService.buffer.ybase - scrollBackSize, 0); - this._bufferService.buffer.ydisp = Math.max(this._bufferService.buffer.ydisp - scrollBackSize, 0); + this._activeBuffer.lines.trimStart(scrollBackSize); + this._activeBuffer.ybase = Math.max(this._activeBuffer.ybase - scrollBackSize, 0); + this._activeBuffer.ydisp = Math.max(this._activeBuffer.ydisp - scrollBackSize, 0); // Force a scroll event to refresh viewport this._onScroll.fire(0); } @@ -1322,16 +1318,16 @@ export class InputHandler extends Disposable implements IInputHandler { this._restrictCursor(this._bufferService.cols); switch (params.params[0]) { case 0: - this._eraseInBufferLine(this._bufferService.buffer.y, this._bufferService.buffer.x, this._bufferService.cols); + this._eraseInBufferLine(this._activeBuffer.y, this._activeBuffer.x, this._bufferService.cols); break; case 1: - this._eraseInBufferLine(this._bufferService.buffer.y, 0, this._bufferService.buffer.x + 1); + this._eraseInBufferLine(this._activeBuffer.y, 0, this._activeBuffer.x + 1); break; case 2: - this._eraseInBufferLine(this._bufferService.buffer.y, 0, this._bufferService.cols); + this._eraseInBufferLine(this._activeBuffer.y, 0, this._bufferService.cols); break; } - this._dirtyRowService.markDirty(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); return true; } @@ -1348,26 +1344,23 @@ export class InputHandler extends Disposable implements IInputHandler { this._restrictCursor(); let param = params.params[0] || 1; - // make buffer local for faster access - const buffer = this._bufferService.buffer; - - if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) { + if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { return true; } - const row: number = buffer.ybase + buffer.y; + const row: number = this._activeBuffer.ybase + this._activeBuffer.y; - const scrollBottomRowsOffset = this._bufferService.rows - 1 - buffer.scrollBottom; - const scrollBottomAbsolute = this._bufferService.rows - 1 + buffer.ybase - scrollBottomRowsOffset + 1; + const scrollBottomRowsOffset = this._bufferService.rows - 1 - this._activeBuffer.scrollBottom; + const scrollBottomAbsolute = this._bufferService.rows - 1 + this._activeBuffer.ybase - scrollBottomRowsOffset + 1; while (param--) { // 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._eraseAttrData())); + this._activeBuffer.lines.splice(scrollBottomAbsolute - 1, 1); + this._activeBuffer.lines.splice(row, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); } - this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom); - buffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? + this._dirtyRowService.markRangeDirty(this._activeBuffer.y, this._activeBuffer.scrollBottom); + this._activeBuffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? return true; } @@ -1384,27 +1377,24 @@ export class InputHandler extends Disposable implements IInputHandler { this._restrictCursor(); let param = params.params[0] || 1; - // make buffer local for faster access - const buffer = this._bufferService.buffer; - - if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) { + if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { return true; } - const row: number = buffer.ybase + buffer.y; + const row: number = this._activeBuffer.ybase + this._activeBuffer.y; let j: number; - j = this._bufferService.rows - 1 - buffer.scrollBottom; - j = this._bufferService.rows - 1 + buffer.ybase - j; + j = this._bufferService.rows - 1 - this._activeBuffer.scrollBottom; + j = this._bufferService.rows - 1 + this._activeBuffer.ybase - j; while (param--) { // 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._eraseAttrData())); + this._activeBuffer.lines.splice(row, 1); + this._activeBuffer.lines.splice(j, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); } - this._dirtyRowService.markRangeDirty(buffer.y, buffer.scrollBottom); - buffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? + this._dirtyRowService.markRangeDirty(this._activeBuffer.y, this._activeBuffer.scrollBottom); + this._activeBuffer.x = 0; // see https://vt100.net/docs/vt220-rm/chapter4.html - vt220 only? return true; } @@ -1421,15 +1411,15 @@ export class InputHandler extends Disposable implements IInputHandler { */ public insertChars(params: IParams): boolean { this._restrictCursor(); - const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + this._bufferService.buffer.y); + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); if (line) { line.insertCells( - this._bufferService.buffer.x, + this._activeBuffer.x, params.params[0] || 1, - this._bufferService.buffer.getNullCell(this._eraseAttrData()), + this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData() ); - this._dirtyRowService.markDirty(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); } return true; } @@ -1447,15 +1437,15 @@ export class InputHandler extends Disposable implements IInputHandler { */ public deleteChars(params: IParams): boolean { this._restrictCursor(); - const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + this._bufferService.buffer.y); + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); if (line) { line.deleteCells( - this._bufferService.buffer.x, + this._activeBuffer.x, params.params[0] || 1, - this._bufferService.buffer.getNullCell(this._eraseAttrData()), + this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData() ); - this._dirtyRowService.markDirty(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); } return true; } @@ -1471,14 +1461,11 @@ export class InputHandler extends Disposable implements IInputHandler { public scrollUp(params: IParams): boolean { let param = params.params[0] || 1; - // make buffer local for faster access - const buffer = this._bufferService.buffer; - while (param--) { - buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1); - buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(this._eraseAttrData())); + this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollTop, 1); + this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollBottom, 0, this._activeBuffer.getBlankLine(this._eraseAttrData())); } - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1490,14 +1477,11 @@ export class InputHandler extends Disposable implements IInputHandler { public scrollDown(params: IParams): boolean { let param = params.params[0] || 1; - // 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(DEFAULT_ATTR_DATA)); + this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollBottom, 1); + this._activeBuffer.lines.splice(this._activeBuffer.ybase + this._activeBuffer.scrollTop, 0, this._activeBuffer.getBlankLine(DEFAULT_ATTR_DATA)); } - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1520,17 +1504,16 @@ export class InputHandler extends Disposable implements IInputHandler { * SL has no effect outside of the scroll margins. */ public scrollLeft(params: IParams): boolean { - const buffer = this._bufferService.buffer; - if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) { + if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { return true; } 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()); + for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; + line.deleteCells(0, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); line.isWrapped = false; } - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1554,17 +1537,16 @@ export class InputHandler extends Disposable implements IInputHandler { * SL has no effect outside of the scroll margins. */ public scrollRight(params: IParams): boolean { - const buffer = this._bufferService.buffer; - if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) { + if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { return true; } 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()); + for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; + line.insertCells(0, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); line.isWrapped = false; } - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1578,17 +1560,16 @@ export class InputHandler extends Disposable implements IInputHandler { * DECIC has no effect outside the scrolling margins. */ public insertColumns(params: IParams): boolean { - const buffer = this._bufferService.buffer; - if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) { + if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { return true; } 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()); + for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; + line.insertCells(this._activeBuffer.x, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); line.isWrapped = false; } - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1602,17 +1583,16 @@ export class InputHandler extends Disposable implements IInputHandler { * DECDC has no effect outside the scrolling margins. */ public deleteColumns(params: IParams): boolean { - const buffer = this._bufferService.buffer; - if (buffer.y > buffer.scrollBottom || buffer.y < buffer.scrollTop) { + if (this._activeBuffer.y > this._activeBuffer.scrollBottom || this._activeBuffer.y < this._activeBuffer.scrollTop) { return true; } 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()); + for (let y = this._activeBuffer.scrollTop; y <= this._activeBuffer.scrollBottom; ++y) { + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; + line.deleteCells(this._activeBuffer.x, param, this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData()); line.isWrapped = false; } - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); return true; } @@ -1626,15 +1606,15 @@ export class InputHandler extends Disposable implements IInputHandler { */ public eraseChars(params: IParams): boolean { this._restrictCursor(); - const line = this._bufferService.buffer.lines.get(this._bufferService.buffer.ybase + this._bufferService.buffer.y); + const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + this._activeBuffer.y); if (line) { line.replaceCells( - this._bufferService.buffer.x, - this._bufferService.buffer.x + (params.params[0] || 1), - this._bufferService.buffer.getNullCell(this._eraseAttrData()), + this._activeBuffer.x, + this._activeBuffer.x + (params.params[0] || 1), + this._activeBuffer.getNullCell(this._eraseAttrData()), this._eraseAttrData() ); - this._dirtyRowService.markDirty(this._bufferService.buffer.y); + this._dirtyRowService.markDirty(this._activeBuffer.y); } return true; } @@ -2570,8 +2550,8 @@ export class InputHandler extends Disposable implements IInputHandler { break; case 6: // cursor position - const y = this._bufferService.buffer.y + 1; - const x = this._bufferService.buffer.x + 1; + const y = this._activeBuffer.y + 1; + const x = this._activeBuffer.x + 1; this._coreService.triggerDataEvent(`${C0.ESC}[${y};${x}R`); break; } @@ -2585,8 +2565,8 @@ export class InputHandler extends Disposable implements IInputHandler { switch (params.params[0]) { case 6: // cursor position - const y = this._bufferService.buffer.y + 1; - const x = this._bufferService.buffer.x + 1; + const y = this._activeBuffer.y + 1; + const x = this._activeBuffer.x + 1; this._coreService.triggerDataEvent(`${C0.ESC}[?${y};${x}R`); break; case 15: @@ -2631,18 +2611,18 @@ export class InputHandler extends Disposable implements IInputHandler { public softReset(params: IParams): boolean { this._coreService.isCursorHidden = false; this._onRequestSyncScrollBar.fire(); - this._bufferService.buffer.scrollTop = 0; - this._bufferService.buffer.scrollBottom = this._bufferService.rows - 1; + this._activeBuffer.scrollTop = 0; + this._activeBuffer.scrollBottom = this._bufferService.rows - 1; this._curAttrData = DEFAULT_ATTR_DATA.clone(); this._coreService.reset(); this._charsetService.reset(); // reset DECSC data - this._bufferService.buffer.savedX = 0; - this._bufferService.buffer.savedY = this._bufferService.buffer.ybase; - this._bufferService.buffer.savedCurAttrData.fg = this._curAttrData.fg; - this._bufferService.buffer.savedCurAttrData.bg = this._curAttrData.bg; - this._bufferService.buffer.savedCharset = this._charsetService.charset; + this._activeBuffer.savedX = 0; + this._activeBuffer.savedY = this._activeBuffer.ybase; + this._activeBuffer.savedCurAttrData.fg = this._curAttrData.fg; + this._activeBuffer.savedCurAttrData.bg = this._curAttrData.bg; + this._activeBuffer.savedCharset = this._charsetService.charset; // reset DECOM this._coreService.decPrivateModes.origin = false; @@ -2705,8 +2685,8 @@ export class InputHandler extends Disposable implements IInputHandler { } if (bottom > top) { - this._bufferService.buffer.scrollTop = top - 1; - this._bufferService.buffer.scrollBottom = bottom - 1; + this._activeBuffer.scrollTop = top - 1; + this._activeBuffer.scrollBottom = bottom - 1; this._setCursor(0, 0); } return true; @@ -2801,11 +2781,11 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y ESC SC "Save Cursor" "ESC 7" "Save cursor position, charmap and text attributes." */ public saveCursor(params?: IParams): boolean { - 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._curAttrData.fg; - this._bufferService.buffer.savedCurAttrData.bg = this._curAttrData.bg; - this._bufferService.buffer.savedCharset = this._charsetService.charset; + this._activeBuffer.savedX = this._activeBuffer.x; + this._activeBuffer.savedY = this._activeBuffer.ybase + this._activeBuffer.y; + this._activeBuffer.savedCurAttrData.fg = this._curAttrData.fg; + this._activeBuffer.savedCurAttrData.bg = this._curAttrData.bg; + this._activeBuffer.savedCharset = this._charsetService.charset; return true; } @@ -2819,13 +2799,13 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y ESC RC "Restore Cursor" "ESC 8" "Restore cursor position, charmap and text attributes." */ public restoreCursor(params?: IParams): boolean { - 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._curAttrData.fg = this._bufferService.buffer.savedCurAttrData.fg; - this._curAttrData.bg = this._bufferService.buffer.savedCurAttrData.bg; + this._activeBuffer.x = this._activeBuffer.savedX || 0; + this._activeBuffer.y = Math.max(this._activeBuffer.savedY - this._activeBuffer.ybase, 0); + this._curAttrData.fg = this._activeBuffer.savedCurAttrData.fg; + this._curAttrData.bg = this._activeBuffer.savedCurAttrData.bg; this._charsetService.charset = (this as any)._savedCharset; - if (this._bufferService.buffer.savedCharset) { - this._charsetService.charset = this._bufferService.buffer.savedCharset; + if (this._activeBuffer.savedCharset) { + this._charsetService.charset = this._activeBuffer.savedCharset; } this._restrictCursor(); return true; @@ -2907,7 +2887,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y ESC NEL "Next Line" "ESC E" "Move the cursor to the beginning of the next row." */ public nextLine(): boolean { - this._bufferService.buffer.x = 0; + this._activeBuffer.x = 0; this.index(); return true; } @@ -2987,13 +2967,12 @@ export class InputHandler extends Disposable implements IInputHandler { */ public index(): boolean { this._restrictCursor(); - const buffer = this._bufferService.buffer; - this._bufferService.buffer.y++; - if (buffer.y === buffer.scrollBottom + 1) { - buffer.y--; + this._activeBuffer.y++; + if (this._activeBuffer.y === this._activeBuffer.scrollBottom + 1) { + this._activeBuffer.y--; this._bufferService.scroll(this._eraseAttrData()); - } else if (buffer.y >= this._bufferService.rows) { - buffer.y = this._bufferService.rows - 1; + } else if (this._activeBuffer.y >= this._bufferService.rows) { + this._activeBuffer.y = this._bufferService.rows - 1; } this._restrictCursor(); return true; @@ -3010,7 +2989,7 @@ export class InputHandler extends Disposable implements IInputHandler { * @vt: #Y ESC HTS "Horizontal Tabulation Set" "ESC H" "Places a tab stop at the current cursor position." */ public tabSet(): boolean { - this._bufferService.buffer.tabs[this._bufferService.buffer.x] = true; + this._activeBuffer.tabs[this._activeBuffer.x] = true; return true; } @@ -3025,17 +3004,16 @@ export class InputHandler extends Disposable implements IInputHandler { */ public reverseIndex(): boolean { this._restrictCursor(); - const buffer = this._bufferService.buffer; - if (buffer.y === buffer.scrollTop) { + if (this._activeBuffer.y === this._activeBuffer.scrollTop) { // possibly move the code below to term.reverseScroll(); // test: echo -ne '\e[1;1H\e[44m\eM\e[0m' // blankLine(true) is xterm/linux behavior - const scrollRegionHeight = buffer.scrollBottom - buffer.scrollTop; - buffer.lines.shiftElements(buffer.ybase + buffer.y, scrollRegionHeight, 1); - buffer.lines.set(buffer.ybase + buffer.y, buffer.getBlankLine(this._eraseAttrData())); - this._dirtyRowService.markRangeDirty(buffer.scrollTop, buffer.scrollBottom); + const scrollRegionHeight = this._activeBuffer.scrollBottom - this._activeBuffer.scrollTop; + this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase + this._activeBuffer.y, scrollRegionHeight, 1); + this._activeBuffer.lines.set(this._activeBuffer.ybase + this._activeBuffer.y, this._activeBuffer.getBlankLine(this._eraseAttrData())); + this._dirtyRowService.markRangeDirty(this._activeBuffer.scrollTop, this._activeBuffer.scrollBottom); } else { - buffer.y--; + this._activeBuffer.y--; this._restrictCursor(); // quickfix to not run out of bounds } return true; @@ -3096,12 +3074,11 @@ export class InputHandler extends Disposable implements IInputHandler { cell.fg = this._curAttrData.fg; cell.bg = this._curAttrData.bg; - const buffer = this._bufferService.buffer; this._setCursor(0, 0); for (let yOffset = 0; yOffset < this._bufferService.rows; ++yOffset) { - const row = buffer.ybase + buffer.y + yOffset; - const line = buffer.lines.get(row); + const row = this._activeBuffer.ybase + this._activeBuffer.y + yOffset; + const line = this._activeBuffer.lines.get(row); if (line) { line.fill(cell); line.isWrapped = false; diff --git a/src/common/buffer/BufferSet.ts b/src/common/buffer/BufferSet.ts index b74c4eac..de220e8f 100644 --- a/src/common/buffer/BufferSet.ts +++ b/src/common/buffer/BufferSet.ts @@ -42,6 +42,10 @@ export class BufferSet extends Disposable implements IBufferSet { // See http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-The-Alternate-Screen-Buffer this._alt = new Buffer(false, this._optionsService, this._bufferService); this._activeBuffer = this._normal; + this._onBufferActivate.fire({ + activeBuffer: this._normal, + inactiveBuffer: this._alt + }); this.setupTabStops(); }