Skip to content

Commit

Permalink
Merge 2f90035 into e4a8464
Browse files Browse the repository at this point in the history
  • Loading branch information
whydoubt committed Nov 18, 2018
2 parents e4a8464 + 2f90035 commit 36810d0
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 23 deletions.
8 changes: 6 additions & 2 deletions src/Buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class Buffer implements IBuffer {
public tabs: any;
public savedY: number;
public savedX: number;
public savedCurAttr: number;
public markers: Marker[] = [];
private _bufferLineConstructor: IBufferLineConstructor;

Expand Down Expand Up @@ -113,11 +114,14 @@ export class Buffer implements IBuffer {
/**
* Fills the buffer's viewport with blank lines.
*/
public fillViewportRows(): void {
public fillViewportRows(fillAttr?: number): void {
if (this.lines.length === 0) {
if (fillAttr === undefined) {
fillAttr = DEFAULT_ATTR;
}
let i = this._terminal.rows;
while (i--) {
this.lines.push(this.getBlankLine(DEFAULT_ATTR));
this.lines.push(this.getBlankLine(fillAttr));
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/BufferSet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,30 @@ describe('BufferSet', () => {
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);
});
});
});
8 changes: 6 additions & 2 deletions src/BufferSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export class BufferSet extends EventEmitter implements IBufferSet {
if (this._activeBuffer === this._normal) {
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
// buffer. This frees up memory since the alt buffer should always be new
// when activated.
Expand All @@ -75,13 +77,15 @@ export class BufferSet extends EventEmitter implements IBufferSet {
/**
* 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) {
return;
}
// Since the alt buffer is always cleared when the normal buffer is
// 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.emit('activate', {
activeBuffer: this._alt,
Expand Down
63 changes: 62 additions & 1 deletion src/InputHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { assert, expect } from 'chai';
import { InputHandler } from './InputHandler';
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 { IBufferLine } from './Types';

Expand Down Expand Up @@ -506,4 +506,65 @@ describe('InputHandler', () => {
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);
});
});
});
43 changes: 29 additions & 14 deletions src/InputHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,9 @@ export class InputHandler extends Disposable implements IInputHandler {
case 66:
this._terminal.log('Serial port requested application keypad.');
this._terminal.applicationKeypad = true;
this._terminal.viewport.syncScrollArea();
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
break;
case 9: // X10 Mouse
// no release, no motion, no wheel, no modifiers.
Expand Down Expand Up @@ -1329,14 +1331,19 @@ export class InputHandler extends Disposable implements IInputHandler {
case 25: // show cursor
this._terminal.cursorHidden = false;
break;
case 1048: // alt screen cursor
this.saveCursor(params);
break;
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
case 47: // alt screen buffer
case 1047: // alt screen buffer
this._terminal.buffers.activateAltBuffer();
this._terminal.viewport.syncScrollArea();
this._terminal.buffers.activateAltBuffer(this._terminal.eraseAttr());
this._terminal.refresh(0, this._terminal.rows - 1);
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._terminal.showCursor();
break;
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
Expand Down Expand Up @@ -1469,7 +1476,9 @@ export class InputHandler extends Disposable implements IInputHandler {
case 66:
this._terminal.log('Switching back to normal keypad.');
this._terminal.applicationKeypad = false;
this._terminal.viewport.syncScrollArea();
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
break;
case 9: // X10 Mouse
case 1000: // vt200 mouse
Expand Down Expand Up @@ -1497,18 +1506,22 @@ export class InputHandler extends Disposable implements IInputHandler {
case 25: // hide cursor
this._terminal.cursorHidden = true;
break;
case 1048: // alt screen cursor
this.restoreCursor(params);
break;
case 1049: // alt screen buffer cursor
// FALL-THROUGH
case 47: // normal screen buffer
case 1047: // normal screen buffer - clearing it first
// Ensure the selection manager has the correct buffer
this._terminal.buffers.activateNormalBuffer();
// TODO: Not sure if we need to save/restore after switching the buffer
// if (params[0] === 1049) {
// this.restoreCursor(params);
// }
if (params[0] === 1049) {
this.restoreCursor(params);
}
this._terminal.refresh(0, this._terminal.rows - 1);
this._terminal.viewport.syncScrollArea();
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._terminal.showCursor();
break;
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
Expand Down Expand Up @@ -1787,7 +1800,9 @@ export class InputHandler extends Disposable implements IInputHandler {
this._terminal.originMode = false;
this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false
this._terminal.applicationKeypad = false; // ?
this._terminal.viewport.syncScrollArea();
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
}
this._terminal.applicationCursor = false;
this._terminal.buffer.scrollTop = 0;
this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
Expand Down Expand Up @@ -1854,7 +1869,7 @@ export class InputHandler extends Disposable implements IInputHandler {
public saveCursor(params: number[]): void {
this._terminal.buffer.savedX = this._terminal.buffer.x;
this._terminal.buffer.savedY = this._terminal.buffer.y;
this._terminal.savedCurAttr = this._terminal.curAttr;
this._terminal.buffer.savedCurAttr = this._terminal.curAttr;
}


Expand All @@ -1866,7 +1881,7 @@ export class InputHandler extends Disposable implements IInputHandler {
public restoreCursor(params: number[]): void {
this._terminal.buffer.x = this._terminal.buffer.savedX || 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;
}


Expand Down
1 change: 0 additions & 1 deletion src/Terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
public savedCols: number;

public curAttr: number;
public savedCurAttr: number;

public params: (string | number)[];
public currentParam: string | number;
Expand Down
4 changes: 2 additions & 2 deletions src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export interface IInputHandlingTerminal extends IEventEmitter {
wraparoundMode: boolean;
bracketedPasteMode: boolean;
curAttr: number;
savedCurAttr: number;
savedCols: number;
x10Mouse: boolean;
vt200Mouse: boolean;
Expand Down Expand Up @@ -290,6 +289,7 @@ export interface IBuffer {
hasScrollback: boolean;
savedY: number;
savedX: number;
savedCurAttr: number;
isCursorInViewport: boolean;
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
getWrappedRangeForLine(y: number): { first: number, last: number };
Expand All @@ -306,7 +306,7 @@ export interface IBufferSet extends IEventEmitter {
active: IBuffer;

activateNormalBuffer(): void;
activateAltBuffer(): void;
activateAltBuffer(fillAttr?: number): void;
}

export interface ISelectionManager {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/TestUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ export class MockInputHandlingTerminal implements IInputHandlingTerminal {
wraparoundMode: boolean;
bracketedPasteMode: boolean;
curAttr: number;
savedCurAttr: number;
savedCols: number;
x10Mouse: boolean;
vt200Mouse: boolean;
Expand Down Expand Up @@ -304,6 +303,7 @@ export class MockBuffer implements IBuffer {
scrollTop: number;
savedY: number;
savedX: number;
savedCurAttr: number;
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string {
return Buffer.prototype.translateBufferLineToString.apply(this, arguments);
}
Expand Down

0 comments on commit 36810d0

Please sign in to comment.