Merge branch 'master' into improve_fill_fallback
This commit is contained in:
+6
-2
@@ -38,6 +38,7 @@ export class Buffer implements IBuffer {
|
|||||||
public tabs: any;
|
public tabs: any;
|
||||||
public savedY: number;
|
public savedY: number;
|
||||||
public savedX: number;
|
public savedX: number;
|
||||||
|
public savedCurAttr: number;
|
||||||
public markers: Marker[] = [];
|
public markers: Marker[] = [];
|
||||||
private _bufferLineConstructor: IBufferLineConstructor;
|
private _bufferLineConstructor: IBufferLineConstructor;
|
||||||
|
|
||||||
@@ -113,11 +114,14 @@ export class Buffer implements IBuffer {
|
|||||||
/**
|
/**
|
||||||
* Fills the buffer's viewport with blank lines.
|
* Fills the buffer's viewport with blank lines.
|
||||||
*/
|
*/
|
||||||
public fillViewportRows(): void {
|
public fillViewportRows(fillAttr?: number): void {
|
||||||
if (this.lines.length === 0) {
|
if (this.lines.length === 0) {
|
||||||
|
if (fillAttr === undefined) {
|
||||||
|
fillAttr = DEFAULT_ATTR;
|
||||||
|
}
|
||||||
let i = this._terminal.rows;
|
let i = this._terminal.rows;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
this.lines.push(this.getBlankLine(DEFAULT_ATTR));
|
this.lines.push(this.getBlankLine(fillAttr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,4 +48,30 @@ describe('BufferSet', () => {
|
|||||||
assert.equal(bufferSet.active, bufferSet.alt);
|
assert.equal(bufferSet.active, bufferSet.alt);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('cursor handling when swapping buffers', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
bufferSet.normal.x = 0;
|
||||||
|
bufferSet.normal.y = 0;
|
||||||
|
bufferSet.alt.x = 0;
|
||||||
|
bufferSet.alt.y = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should keep the cursor stationary when activating alt buffer', () => {
|
||||||
|
bufferSet.activateNormalBuffer();
|
||||||
|
bufferSet.active.x = 30;
|
||||||
|
bufferSet.active.y = 10;
|
||||||
|
bufferSet.activateAltBuffer();
|
||||||
|
assert.equal(bufferSet.active.x, 30);
|
||||||
|
assert.equal(bufferSet.active.y, 10);
|
||||||
|
});
|
||||||
|
it('should keep the cursor stationary when activating normal buffer', () => {
|
||||||
|
bufferSet.activateAltBuffer();
|
||||||
|
bufferSet.active.x = 30;
|
||||||
|
bufferSet.active.y = 10;
|
||||||
|
bufferSet.activateNormalBuffer();
|
||||||
|
assert.equal(bufferSet.active.x, 30);
|
||||||
|
assert.equal(bufferSet.active.y, 10);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+6
-2
@@ -61,6 +61,8 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
|||||||
if (this._activeBuffer === this._normal) {
|
if (this._activeBuffer === this._normal) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this._normal.x = this._alt.x;
|
||||||
|
this._normal.y = this._alt.y;
|
||||||
// The alt buffer should always be cleared when we switch to the normal
|
// The alt buffer should always be cleared when we switch to the normal
|
||||||
// buffer. This frees up memory since the alt buffer should always be new
|
// buffer. This frees up memory since the alt buffer should always be new
|
||||||
// when activated.
|
// when activated.
|
||||||
@@ -75,13 +77,15 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
|||||||
/**
|
/**
|
||||||
* Sets the alt Buffer of the BufferSet as its currently active Buffer
|
* Sets the alt Buffer of the BufferSet as its currently active Buffer
|
||||||
*/
|
*/
|
||||||
public activateAltBuffer(): void {
|
public activateAltBuffer(fillAttr?: number): void {
|
||||||
if (this._activeBuffer === this._alt) {
|
if (this._activeBuffer === this._alt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Since the alt buffer is always cleared when the normal buffer is
|
// Since the alt buffer is always cleared when the normal buffer is
|
||||||
// activated, we want to fill it when switching to it.
|
// activated, we want to fill it when switching to it.
|
||||||
this._alt.fillViewportRows();
|
this._alt.fillViewportRows(fillAttr);
|
||||||
|
this._alt.x = this._normal.x;
|
||||||
|
this._alt.y = this._normal.y;
|
||||||
this._activeBuffer = this._alt;
|
this._activeBuffer = this._alt;
|
||||||
this.emit('activate', {
|
this.emit('activate', {
|
||||||
activeBuffer: this._alt,
|
activeBuffer: this._alt,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { assert, expect } from 'chai';
|
import { assert, expect } from 'chai';
|
||||||
import { InputHandler } from './InputHandler';
|
import { InputHandler } from './InputHandler';
|
||||||
import { MockInputHandlingTerminal } from './utils/TestUtils.test';
|
import { MockInputHandlingTerminal } from './utils/TestUtils.test';
|
||||||
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, CHAR_DATA_CHAR_INDEX } from './Buffer';
|
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, DEFAULT_ATTR } from './Buffer';
|
||||||
import { Terminal } from './Terminal';
|
import { Terminal } from './Terminal';
|
||||||
import { IBufferLine } from './Types';
|
import { IBufferLine } from './Types';
|
||||||
|
|
||||||
@@ -506,4 +506,65 @@ describe('InputHandler', () => {
|
|||||||
inputHandler.print(String.fromCharCode(0x200B), 0, 1);
|
inputHandler.print(String.fromCharCode(0x200B), 0, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('alt screen', () => {
|
||||||
|
let term: Terminal;
|
||||||
|
let handler: InputHandler;
|
||||||
|
|
||||||
|
function lineContent(line: IBufferLine): string {
|
||||||
|
let content = '';
|
||||||
|
for (let i = 0; i < line.length; ++i) content += line.get(i)[CHAR_DATA_CHAR_INDEX];
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
term = new Terminal();
|
||||||
|
handler = new InputHandler(term);
|
||||||
|
});
|
||||||
|
it('should handle DECSET/DECRST 47 (alt screen buffer)', () => {
|
||||||
|
handler.parse('\x1b[?47h\r\n\x1b[31mJUNK\x1b[?47lTEST');
|
||||||
|
expect(lineContent(term.buffer.lines.get(0))).to.equal(Array(term.cols + 1).join(' '));
|
||||||
|
expect(lineContent(term.buffer.lines.get(1))).to.equal(' TEST' + Array(term.cols - 7).join(' '));
|
||||||
|
// Text color of 'TEST' should be red
|
||||||
|
expect((term.buffer.lines.get(1).get(4)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||||
|
});
|
||||||
|
it('should handle DECSET/DECRST 1047 (alt screen buffer)', () => {
|
||||||
|
handler.parse('\x1b[?1047h\r\n\x1b[31mJUNK\x1b[?1047lTEST');
|
||||||
|
expect(lineContent(term.buffer.lines.get(0))).to.equal(Array(term.cols + 1).join(' '));
|
||||||
|
expect(lineContent(term.buffer.lines.get(1))).to.equal(' TEST' + Array(term.cols - 7).join(' '));
|
||||||
|
// Text color of 'TEST' should be red
|
||||||
|
expect((term.buffer.lines.get(1).get(4)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||||
|
});
|
||||||
|
it('should handle DECSET/DECRST 1048 (alt screen cursor)', () => {
|
||||||
|
handler.parse('\x1b[?1048h\r\n\x1b[31mJUNK\x1b[?1048lTEST');
|
||||||
|
expect(lineContent(term.buffer.lines.get(0))).to.equal('TEST' + Array(term.cols - 3).join(' '));
|
||||||
|
expect(lineContent(term.buffer.lines.get(1))).to.equal('JUNK' + Array(term.cols - 3).join(' '));
|
||||||
|
// Text color of 'TEST' should be default
|
||||||
|
expect(term.buffer.lines.get(0).get(0)[CHAR_DATA_ATTR_INDEX]).to.equal(DEFAULT_ATTR);
|
||||||
|
// Text color of 'JUNK' should be red
|
||||||
|
expect((term.buffer.lines.get(1).get(0)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||||
|
});
|
||||||
|
it('should handle DECSET/DECRST 1049 (alt screen buffer+cursor)', () => {
|
||||||
|
handler.parse('\x1b[?1049h\r\n\x1b[31mJUNK\x1b[?1049lTEST');
|
||||||
|
expect(lineContent(term.buffer.lines.get(0))).to.equal('TEST' + Array(term.cols - 3).join(' '));
|
||||||
|
expect(lineContent(term.buffer.lines.get(1))).to.equal(Array(term.cols + 1).join(' '));
|
||||||
|
// Text color of 'TEST' should be default
|
||||||
|
expect(term.buffer.lines.get(0).get(0)[CHAR_DATA_ATTR_INDEX]).to.equal(DEFAULT_ATTR);
|
||||||
|
});
|
||||||
|
it('should handle DECSET/DECRST 1049 - maintains saved cursor for alt buffer', () => {
|
||||||
|
handler.parse('\x1b[?1049h\r\n\x1b[31m\x1b[s\x1b[?1049lTEST');
|
||||||
|
expect(lineContent(term.buffer.lines.get(0))).to.equal('TEST' + Array(term.cols - 3).join(' '));
|
||||||
|
// Text color of 'TEST' should be default
|
||||||
|
expect(term.buffer.lines.get(0).get(0)[CHAR_DATA_ATTR_INDEX]).to.equal(DEFAULT_ATTR);
|
||||||
|
handler.parse('\x1b[?1049h\x1b[uTEST');
|
||||||
|
expect(lineContent(term.buffer.lines.get(1))).to.equal('TEST' + Array(term.cols - 3).join(' '));
|
||||||
|
// Text color of 'TEST' should be red
|
||||||
|
expect((term.buffer.lines.get(1).get(0)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||||
|
});
|
||||||
|
it('should handle DECSET/DECRST 1049 - clears alt buffer with erase attributes', () => {
|
||||||
|
handler.parse('\x1b[42m\x1b[?1049h');
|
||||||
|
// Buffer should be filled with green background
|
||||||
|
expect(term.buffer.lines.get(20).get(10)[CHAR_DATA_ATTR_INDEX] & 0x1ff).to.equal(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+29
-14
@@ -1284,7 +1284,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
case 66:
|
case 66:
|
||||||
this._terminal.log('Serial port requested application keypad.');
|
this._terminal.log('Serial port requested application keypad.');
|
||||||
this._terminal.applicationKeypad = true;
|
this._terminal.applicationKeypad = true;
|
||||||
this._terminal.viewport.syncScrollArea();
|
if (this._terminal.viewport) {
|
||||||
|
this._terminal.viewport.syncScrollArea();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 9: // X10 Mouse
|
case 9: // X10 Mouse
|
||||||
// no release, no motion, no wheel, no modifiers.
|
// no release, no motion, no wheel, no modifiers.
|
||||||
@@ -1333,14 +1335,19 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
case 25: // show cursor
|
case 25: // show cursor
|
||||||
this._terminal.cursorHidden = false;
|
this._terminal.cursorHidden = false;
|
||||||
break;
|
break;
|
||||||
|
case 1048: // alt screen cursor
|
||||||
|
this.saveCursor(params);
|
||||||
|
break;
|
||||||
case 1049: // alt screen buffer cursor
|
case 1049: // alt screen buffer cursor
|
||||||
// TODO: Not sure if we need to save/restore after switching the buffer
|
this.saveCursor(params);
|
||||||
// this.saveCursor(params);
|
|
||||||
// FALL-THROUGH
|
// FALL-THROUGH
|
||||||
case 47: // alt screen buffer
|
case 47: // alt screen buffer
|
||||||
case 1047: // alt screen buffer
|
case 1047: // alt screen buffer
|
||||||
this._terminal.buffers.activateAltBuffer();
|
this._terminal.buffers.activateAltBuffer(this._terminal.eraseAttr());
|
||||||
this._terminal.viewport.syncScrollArea();
|
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||||
|
if (this._terminal.viewport) {
|
||||||
|
this._terminal.viewport.syncScrollArea();
|
||||||
|
}
|
||||||
this._terminal.showCursor();
|
this._terminal.showCursor();
|
||||||
break;
|
break;
|
||||||
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
|
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
|
||||||
@@ -1473,7 +1480,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
case 66:
|
case 66:
|
||||||
this._terminal.log('Switching back to normal keypad.');
|
this._terminal.log('Switching back to normal keypad.');
|
||||||
this._terminal.applicationKeypad = false;
|
this._terminal.applicationKeypad = false;
|
||||||
this._terminal.viewport.syncScrollArea();
|
if (this._terminal.viewport) {
|
||||||
|
this._terminal.viewport.syncScrollArea();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 9: // X10 Mouse
|
case 9: // X10 Mouse
|
||||||
case 1000: // vt200 mouse
|
case 1000: // vt200 mouse
|
||||||
@@ -1501,18 +1510,22 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
case 25: // hide cursor
|
case 25: // hide cursor
|
||||||
this._terminal.cursorHidden = true;
|
this._terminal.cursorHidden = true;
|
||||||
break;
|
break;
|
||||||
|
case 1048: // alt screen cursor
|
||||||
|
this.restoreCursor(params);
|
||||||
|
break;
|
||||||
case 1049: // alt screen buffer cursor
|
case 1049: // alt screen buffer cursor
|
||||||
// FALL-THROUGH
|
// FALL-THROUGH
|
||||||
case 47: // normal screen buffer
|
case 47: // normal screen buffer
|
||||||
case 1047: // normal screen buffer - clearing it first
|
case 1047: // normal screen buffer - clearing it first
|
||||||
// Ensure the selection manager has the correct buffer
|
// Ensure the selection manager has the correct buffer
|
||||||
this._terminal.buffers.activateNormalBuffer();
|
this._terminal.buffers.activateNormalBuffer();
|
||||||
// TODO: Not sure if we need to save/restore after switching the buffer
|
if (params[0] === 1049) {
|
||||||
// if (params[0] === 1049) {
|
this.restoreCursor(params);
|
||||||
// this.restoreCursor(params);
|
}
|
||||||
// }
|
|
||||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||||
this._terminal.viewport.syncScrollArea();
|
if (this._terminal.viewport) {
|
||||||
|
this._terminal.viewport.syncScrollArea();
|
||||||
|
}
|
||||||
this._terminal.showCursor();
|
this._terminal.showCursor();
|
||||||
break;
|
break;
|
||||||
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
|
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
|
||||||
@@ -1791,7 +1804,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
this._terminal.originMode = false;
|
this._terminal.originMode = false;
|
||||||
this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false
|
this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false
|
||||||
this._terminal.applicationKeypad = false; // ?
|
this._terminal.applicationKeypad = false; // ?
|
||||||
this._terminal.viewport.syncScrollArea();
|
if (this._terminal.viewport) {
|
||||||
|
this._terminal.viewport.syncScrollArea();
|
||||||
|
}
|
||||||
this._terminal.applicationCursor = false;
|
this._terminal.applicationCursor = false;
|
||||||
this._terminal.buffer.scrollTop = 0;
|
this._terminal.buffer.scrollTop = 0;
|
||||||
this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
|
this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
|
||||||
@@ -1858,7 +1873,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
public saveCursor(params: number[]): void {
|
public saveCursor(params: number[]): void {
|
||||||
this._terminal.buffer.savedX = this._terminal.buffer.x;
|
this._terminal.buffer.savedX = this._terminal.buffer.x;
|
||||||
this._terminal.buffer.savedY = this._terminal.buffer.y;
|
this._terminal.buffer.savedY = this._terminal.buffer.y;
|
||||||
this._terminal.savedCurAttr = this._terminal.curAttr;
|
this._terminal.buffer.savedCurAttr = this._terminal.curAttr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1870,7 +1885,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
|||||||
public restoreCursor(params: number[]): void {
|
public restoreCursor(params: number[]): void {
|
||||||
this._terminal.buffer.x = this._terminal.buffer.savedX || 0;
|
this._terminal.buffer.x = this._terminal.buffer.savedX || 0;
|
||||||
this._terminal.buffer.y = this._terminal.buffer.savedY || 0;
|
this._terminal.buffer.y = this._terminal.buffer.savedY || 0;
|
||||||
this._terminal.curAttr = this._terminal.savedCurAttr || DEFAULT_ATTR;
|
this._terminal.curAttr = this._terminal.buffer.savedCurAttr || DEFAULT_ATTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -170,7 +170,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
|
|||||||
public savedCols: number;
|
public savedCols: number;
|
||||||
|
|
||||||
public curAttr: number;
|
public curAttr: number;
|
||||||
public savedCurAttr: number;
|
|
||||||
|
|
||||||
public params: (string | number)[];
|
public params: (string | number)[];
|
||||||
public currentParam: string | number;
|
public currentParam: string | number;
|
||||||
|
|||||||
+2
-2
@@ -49,7 +49,6 @@ export interface IInputHandlingTerminal extends IEventEmitter {
|
|||||||
wraparoundMode: boolean;
|
wraparoundMode: boolean;
|
||||||
bracketedPasteMode: boolean;
|
bracketedPasteMode: boolean;
|
||||||
curAttr: number;
|
curAttr: number;
|
||||||
savedCurAttr: number;
|
|
||||||
savedCols: number;
|
savedCols: number;
|
||||||
x10Mouse: boolean;
|
x10Mouse: boolean;
|
||||||
vt200Mouse: boolean;
|
vt200Mouse: boolean;
|
||||||
@@ -290,6 +289,7 @@ export interface IBuffer {
|
|||||||
hasScrollback: boolean;
|
hasScrollback: boolean;
|
||||||
savedY: number;
|
savedY: number;
|
||||||
savedX: number;
|
savedX: number;
|
||||||
|
savedCurAttr: number;
|
||||||
isCursorInViewport: boolean;
|
isCursorInViewport: boolean;
|
||||||
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
|
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
|
||||||
getWrappedRangeForLine(y: number): { first: number, last: number };
|
getWrappedRangeForLine(y: number): { first: number, last: number };
|
||||||
@@ -306,7 +306,7 @@ export interface IBufferSet extends IEventEmitter {
|
|||||||
active: IBuffer;
|
active: IBuffer;
|
||||||
|
|
||||||
activateNormalBuffer(): void;
|
activateNormalBuffer(): void;
|
||||||
activateAltBuffer(): void;
|
activateAltBuffer(fillAttr?: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISelectionManager {
|
export interface ISelectionManager {
|
||||||
|
|||||||
@@ -182,7 +182,6 @@ export class MockInputHandlingTerminal implements IInputHandlingTerminal {
|
|||||||
wraparoundMode: boolean;
|
wraparoundMode: boolean;
|
||||||
bracketedPasteMode: boolean;
|
bracketedPasteMode: boolean;
|
||||||
curAttr: number;
|
curAttr: number;
|
||||||
savedCurAttr: number;
|
|
||||||
savedCols: number;
|
savedCols: number;
|
||||||
x10Mouse: boolean;
|
x10Mouse: boolean;
|
||||||
vt200Mouse: boolean;
|
vt200Mouse: boolean;
|
||||||
@@ -304,6 +303,7 @@ export class MockBuffer implements IBuffer {
|
|||||||
scrollTop: number;
|
scrollTop: number;
|
||||||
savedY: number;
|
savedY: number;
|
||||||
savedX: number;
|
savedX: number;
|
||||||
|
savedCurAttr: number;
|
||||||
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string {
|
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string {
|
||||||
return Buffer.prototype.translateBufferLineToString.apply(this, arguments);
|
return Buffer.prototype.translateBufferLineToString.apply(this, arguments);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user