Use IBufferService for buffer access in InputHandler

This commit is contained in:
Daniel Imms
2019-07-13 00:52:54 -07:00
parent 61b219ce22
commit dd239b9811
3 changed files with 246 additions and 234 deletions
+139 -131
View File
@@ -13,7 +13,8 @@ import { CellData } from 'common/buffer/CellData';
import { Attributes } from 'common/buffer/Constants';
import { AttributeData } from 'common/buffer/AttributeData';
import { Params } from 'common/parser/Params';
import { MockCoreService } from 'common/TestUtils.test';
import { MockCoreService, MockBufferService } from 'common/TestUtils.test';
import { IBufferService } from 'common/services/Services';
function getCursor(term: TestTerminal): number[] {
return [
@@ -27,30 +28,31 @@ describe('InputHandler', () => {
const terminal = new MockInputHandlingTerminal();
terminal.cols = 80;
terminal.rows = 30;
terminal.buffer.x = 1;
terminal.buffer.y = 2;
terminal.buffer.ybase = 0;
terminal.curAttrData.fg = 3;
const inputHandler = new InputHandler(terminal, new MockCoreService());
const bufferService = new MockBufferService(80, 30);
bufferService.buffer.x = 1;
bufferService.buffer.y = 2;
bufferService.buffer.ybase = 0;
const inputHandler = new InputHandler(terminal, bufferService, new MockCoreService());
// Save cursor position
inputHandler.saveCursor();
assert.equal(terminal.buffer.x, 1);
assert.equal(terminal.buffer.y, 2);
assert.equal(bufferService.buffer.x, 1);
assert.equal(bufferService.buffer.y, 2);
assert.equal(terminal.curAttrData.fg, 3);
// Change cursor position
terminal.buffer.x = 10;
terminal.buffer.y = 20;
bufferService.buffer.x = 10;
bufferService.buffer.y = 20;
terminal.curAttrData.fg = 30;
// Restore cursor position
inputHandler.restoreCursor();
assert.equal(terminal.buffer.x, 1);
assert.equal(terminal.buffer.y, 2);
assert.equal(bufferService.buffer.x, 1);
assert.equal(bufferService.buffer.y, 2);
assert.equal(terminal.curAttrData.fg, 3);
});
describe('setCursorStyle', () => {
it('should call Terminal.setOption with correct params', () => {
const terminal = new MockInputHandlingTerminal();
const inputHandler = new InputHandler(terminal, new MockCoreService());
const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService());
const collect = ' ';
inputHandler.setCursorStyle(Params.fromArray([0]), collect);
@@ -93,7 +95,7 @@ describe('InputHandler', () => {
const terminal = new MockInputHandlingTerminal();
const collect = '?';
terminal.bracketedPasteMode = false;
const inputHandler = new InputHandler(terminal, new MockCoreService());
const inputHandler = new InputHandler(terminal, new MockBufferService(80, 30), new MockCoreService());
// Set bracketed paste mode
inputHandler.setMode(Params.fromArray([2004]), collect);
assert.equal(terminal.bracketedPasteMode, true);
@@ -103,92 +105,95 @@ describe('InputHandler', () => {
});
});
describe('regression tests', function(): void {
function termContent(term: Terminal, trim: boolean): string[] {
function termContent(bufferService: IBufferService, trim: boolean): string[] {
const result = [];
for (let i = 0; i < term.rows; ++i) result.push(term.buffer.lines.get(i).translateToString(trim));
for (let i = 0; i < bufferService.rows; ++i) result.push(bufferService.buffer.lines.get(i).translateToString(trim));
return result;
}
it('insertChars', function(): void {
const term = new Terminal();
const inputHandler = new InputHandler(term, new MockCoreService());
const bufferService = new MockBufferService(80, 30);
const inputHandler = new InputHandler(term, bufferService, new MockCoreService());
// insert some data in first and second line
inputHandler.parse(Array(term.cols - 9).join('a'));
inputHandler.parse('1234567890');
inputHandler.parse(Array(term.cols - 9).join('a'));
inputHandler.parse('1234567890');
const line1: IBufferLine = term.buffer.lines.get(0);
const line1: IBufferLine = bufferService.buffer.lines.get(0);
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + '1234567890');
// insert one char from params = [0]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.insertChars(Params.fromArray([0]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + ' 123456789');
// insert one char from params = [1]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.insertChars(Params.fromArray([1]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + ' 12345678');
// insert two chars from params = [2]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.insertChars(Params.fromArray([2]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + ' 123456');
// insert 10 chars from params = [10]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.insertChars(Params.fromArray([10]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + ' ');
expect(line1.translateToString(true)).equals(Array(term.cols - 9).join('a'));
});
it('deleteChars', function(): void {
const term = new Terminal();
const inputHandler = new InputHandler(term, new MockCoreService());
const bufferService = new MockBufferService(80, 30);
const inputHandler = new InputHandler(term, bufferService, new MockCoreService());
// insert some data in first and second line
inputHandler.parse(Array(term.cols - 9).join('a'));
inputHandler.parse('1234567890');
inputHandler.parse(Array(term.cols - 9).join('a'));
inputHandler.parse('1234567890');
const line1: IBufferLine = term.buffer.lines.get(0);
const line1: IBufferLine = bufferService.buffer.lines.get(0);
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + '1234567890');
// delete one char from params = [0]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.deleteChars(Params.fromArray([0]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + '234567890 ');
expect(line1.translateToString(true)).equals(Array(term.cols - 9).join('a') + '234567890');
// insert one char from params = [1]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.deleteChars(Params.fromArray([1]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + '34567890 ');
expect(line1.translateToString(true)).equals(Array(term.cols - 9).join('a') + '34567890');
// insert two chars from params = [2]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.deleteChars(Params.fromArray([2]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + '567890 ');
expect(line1.translateToString(true)).equals(Array(term.cols - 9).join('a') + '567890');
// insert 10 chars from params = [10]
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.deleteChars(Params.fromArray([10]));
expect(line1.translateToString(false)).equals(Array(term.cols - 9).join('a') + ' ');
expect(line1.translateToString(true)).equals(Array(term.cols - 9).join('a'));
});
it('eraseInLine', function(): void {
const term = new Terminal();
const inputHandler = new InputHandler(term, new MockCoreService());
const bufferService = new MockBufferService(80, 30);
const inputHandler = new InputHandler(term, bufferService, new MockCoreService());
// fill 6 lines to test 3 different states
inputHandler.parse(Array(term.cols + 1).join('a'));
@@ -196,101 +201,102 @@ describe('InputHandler', () => {
inputHandler.parse(Array(term.cols + 1).join('a'));
// params[0] - right erase
term.buffer.y = 0;
term.buffer.x = 70;
bufferService.buffer.y = 0;
bufferService.buffer.x = 70;
inputHandler.eraseInLine(Params.fromArray([0]));
expect(term.buffer.lines.get(0).translateToString(false)).equals(Array(71).join('a') + ' ');
expect(bufferService.buffer.lines.get(0).translateToString(false)).equals(Array(71).join('a') + ' ');
// params[1] - left erase
term.buffer.y = 1;
term.buffer.x = 70;
bufferService.buffer.y = 1;
bufferService.buffer.x = 70;
inputHandler.eraseInLine(Params.fromArray([1]));
expect(term.buffer.lines.get(1).translateToString(false)).equals(Array(71).join(' ') + ' aaaaaaaaa');
expect(bufferService.buffer.lines.get(1).translateToString(false)).equals(Array(71).join(' ') + ' aaaaaaaaa');
// params[1] - left erase
term.buffer.y = 2;
term.buffer.x = 70;
bufferService.buffer.y = 2;
bufferService.buffer.x = 70;
inputHandler.eraseInLine(Params.fromArray([2]));
expect(term.buffer.lines.get(2).translateToString(false)).equals(Array(term.cols + 1).join(' '));
expect(bufferService.buffer.lines.get(2).translateToString(false)).equals(Array(term.cols + 1).join(' '));
});
it('eraseInDisplay', function(): void {
const term = new Terminal({cols: 80, rows: 7});
const inputHandler = new InputHandler(term, new MockCoreService());
const bufferService = new MockBufferService(80, 7);
const inputHandler = new InputHandler(term, bufferService, new MockCoreService());
// fill display with a's
for (let i = 0; i < term.rows; ++i) inputHandler.parse(Array(term.cols + 1).join('a'));
for (let i = 0; i < term.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a'));
// params [0] - right and below erase
term.buffer.y = 5;
term.buffer.x = 40;
bufferService.buffer.y = 5;
bufferService.buffer.x = 40;
inputHandler.eraseInDisplay(Params.fromArray([0]));
expect(termContent(term, false)).eql([
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(40 + 1).join('a') + Array(term.cols - 40 + 1).join(' '),
Array(term.cols + 1).join(' ')
expect(termContent(bufferService, false)).eql([
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(40 + 1).join('a') + Array(bufferService.cols - 40 + 1).join(' '),
Array(bufferService.cols + 1).join(' ')
]);
expect(termContent(term, true)).eql([
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
Array(term.cols + 1).join('a'),
expect(termContent(bufferService, true)).eql([
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(bufferService.cols + 1).join('a'),
Array(40 + 1).join('a'),
''
]);
// reset
term.buffer.y = 0;
term.buffer.x = 0;
for (let i = 0; i < term.rows; ++i) inputHandler.parse(Array(term.cols + 1).join('a'));
bufferService.buffer.y = 0;
bufferService.buffer.x = 0;
for (let i = 0; i < bufferService.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a'));
// params [1] - left and above
term.buffer.y = 5;
term.buffer.x = 40;
bufferService.buffer.y = 5;
bufferService.buffer.x = 40;
inputHandler.eraseInDisplay(Params.fromArray([1]));
expect(termContent(term, false)).eql([
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(41 + 1).join(' ') + Array(term.cols - 41 + 1).join('a'),
Array(term.cols + 1).join('a')
expect(termContent(bufferService, false)).eql([
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(41 + 1).join(' ') + Array(bufferService.cols - 41 + 1).join('a'),
Array(bufferService.cols + 1).join('a')
]);
expect(termContent(term, true)).eql([
expect(termContent(bufferService, true)).eql([
'',
'',
'',
'',
'',
Array(41 + 1).join(' ') + Array(term.cols - 41 + 1).join('a'),
Array(term.cols + 1).join('a')
Array(41 + 1).join(' ') + Array(bufferService.cols - 41 + 1).join('a'),
Array(bufferService.cols + 1).join('a')
]);
// reset
term.buffer.y = 0;
term.buffer.x = 0;
for (let i = 0; i < term.rows; ++i) inputHandler.parse(Array(term.cols + 1).join('a'));
bufferService.buffer.y = 0;
bufferService.buffer.x = 0;
for (let i = 0; i < bufferService.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a'));
// params [2] - whole screen
term.buffer.y = 5;
term.buffer.x = 40;
bufferService.buffer.y = 5;
bufferService.buffer.x = 40;
inputHandler.eraseInDisplay(Params.fromArray([2]));
expect(termContent(term, false)).eql([
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' '),
Array(term.cols + 1).join(' ')
expect(termContent(bufferService, false)).eql([
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' '),
Array(bufferService.cols + 1).join(' ')
]);
expect(termContent(term, true)).eql([
expect(termContent(bufferService, true)).eql([
'',
'',
'',
@@ -301,34 +307,34 @@ describe('InputHandler', () => {
]);
// reset and add a wrapped line
term.buffer.y = 0;
term.buffer.x = 0;
inputHandler.parse(Array(term.cols + 1).join('a')); // line 0
inputHandler.parse(Array(term.cols + 10).join('a')); // line 1 and 2
for (let i = 3; i < term.rows; ++i) inputHandler.parse(Array(term.cols + 1).join('a'));
bufferService.buffer.y = 0;
bufferService.buffer.x = 0;
inputHandler.parse(Array(bufferService.cols + 1).join('a')); // line 0
inputHandler.parse(Array(bufferService.cols + 10).join('a')); // line 1 and 2
for (let i = 3; i < bufferService.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a'));
// params[1] left and above with wrap
// confirm precondition that line 2 is wrapped
expect(term.buffer.lines.get(2).isWrapped).true;
term.buffer.y = 2;
term.buffer.x = 40;
expect(bufferService.buffer.lines.get(2).isWrapped).true;
bufferService.buffer.y = 2;
bufferService.buffer.x = 40;
inputHandler.eraseInDisplay(Params.fromArray([1]));
expect(term.buffer.lines.get(2).isWrapped).false;
expect(bufferService.buffer.lines.get(2).isWrapped).false;
// reset and add a wrapped line
term.buffer.y = 0;
term.buffer.x = 0;
inputHandler.parse(Array(term.cols + 1).join('a')); // line 0
inputHandler.parse(Array(term.cols + 10).join('a')); // line 1 and 2
for (let i = 3; i < term.rows; ++i) inputHandler.parse(Array(term.cols + 1).join('a'));
bufferService.buffer.y = 0;
bufferService.buffer.x = 0;
inputHandler.parse(Array(bufferService.cols + 1).join('a')); // line 0
inputHandler.parse(Array(bufferService.cols + 10).join('a')); // line 1 and 2
for (let i = 3; i < bufferService.rows; ++i) inputHandler.parse(Array(bufferService.cols + 1).join('a'));
// params[1] left and above with wrap
// confirm precondition that line 2 is wrapped
expect(term.buffer.lines.get(2).isWrapped).true;
term.buffer.y = 1;
term.buffer.x = 90; // Cursor is beyond last column
expect(bufferService.buffer.lines.get(2).isWrapped).true;
bufferService.buffer.y = 1;
bufferService.buffer.x = 90; // Cursor is beyond last column
inputHandler.eraseInDisplay(Params.fromArray([1]));
expect(term.buffer.lines.get(2).isWrapped).false;
expect(bufferService.buffer.lines.get(2).isWrapped).false;
});
});
it('convertEol setting', function(): void {
@@ -351,7 +357,7 @@ describe('InputHandler', () => {
describe('print', () => {
it('should not cause an infinite loop (regression test)', () => {
const term = new Terminal();
const inputHandler = new InputHandler(term, new MockCoreService());
const inputHandler = new InputHandler(term, new MockBufferService(80, 30), new MockCoreService());
const container = new Uint32Array(10);
container[0] = 0x200B;
inputHandler.print(container, 0, 1);
@@ -360,56 +366,58 @@ describe('InputHandler', () => {
describe('alt screen', () => {
let term: Terminal;
let bufferService: IBufferService;
let handler: InputHandler;
beforeEach(() => {
term = new Terminal();
handler = new InputHandler(term, new MockCoreService());
bufferService = new MockBufferService(80, 30);
handler = new InputHandler(term, bufferService, new MockCoreService());
});
it('should handle DECSET/DECRST 47 (alt screen buffer)', () => {
handler.parse('\x1b[?47h\r\n\x1b[31mJUNK\x1b[?47lTEST');
expect(term.buffer.translateBufferLineToString(0, true)).to.equal('');
expect(term.buffer.translateBufferLineToString(1, true)).to.equal(' TEST');
expect(bufferService.buffer.translateBufferLineToString(0, true)).to.equal('');
expect(bufferService.buffer.translateBufferLineToString(1, true)).to.equal(' TEST');
// Text color of 'TEST' should be red
expect((term.buffer.lines.get(1).loadCell(4, new CellData()).getFgColor())).to.equal(1);
expect((bufferService.buffer.lines.get(1).loadCell(4, new CellData()).getFgColor())).to.equal(1);
});
it('should handle DECSET/DECRST 1047 (alt screen buffer)', () => {
handler.parse('\x1b[?1047h\r\n\x1b[31mJUNK\x1b[?1047lTEST');
expect(term.buffer.translateBufferLineToString(0, true)).to.equal('');
expect(term.buffer.translateBufferLineToString(1, true)).to.equal(' TEST');
expect(bufferService.buffer.translateBufferLineToString(0, true)).to.equal('');
expect(bufferService.buffer.translateBufferLineToString(1, true)).to.equal(' TEST');
// Text color of 'TEST' should be red
expect((term.buffer.lines.get(1).loadCell(4, new CellData()).getFgColor())).to.equal(1);
expect((bufferService.buffer.lines.get(1).loadCell(4, new CellData()).getFgColor())).to.equal(1);
});
it('should handle DECSET/DECRST 1048 (alt screen cursor)', () => {
handler.parse('\x1b[?1048h\r\n\x1b[31mJUNK\x1b[?1048lTEST');
expect(term.buffer.translateBufferLineToString(0, true)).to.equal('TEST');
expect(term.buffer.translateBufferLineToString(1, true)).to.equal('JUNK');
expect(bufferService.buffer.translateBufferLineToString(0, true)).to.equal('TEST');
expect(bufferService.buffer.translateBufferLineToString(1, true)).to.equal('JUNK');
// Text color of 'TEST' should be default
expect(term.buffer.lines.get(0).loadCell(0, new CellData()).fg).to.equal(DEFAULT_ATTR_DATA.fg);
expect(bufferService.buffer.lines.get(0).loadCell(0, new CellData()).fg).to.equal(DEFAULT_ATTR_DATA.fg);
// Text color of 'JUNK' should be red
expect((term.buffer.lines.get(1).loadCell(0, new CellData()).getFgColor())).to.equal(1);
expect((bufferService.buffer.lines.get(1).loadCell(0, new CellData()).getFgColor())).to.equal(1);
});
it('should handle DECSET/DECRST 1049 (alt screen buffer+cursor)', () => {
handler.parse('\x1b[?1049h\r\n\x1b[31mJUNK\x1b[?1049lTEST');
expect(term.buffer.translateBufferLineToString(0, true)).to.equal('TEST');
expect(term.buffer.translateBufferLineToString(1, true)).to.equal('');
expect(bufferService.buffer.translateBufferLineToString(0, true)).to.equal('TEST');
expect(bufferService.buffer.translateBufferLineToString(1, true)).to.equal('');
// Text color of 'TEST' should be default
expect(term.buffer.lines.get(0).loadCell(0, new CellData()).fg).to.equal(DEFAULT_ATTR_DATA.fg);
expect(bufferService.buffer.lines.get(0).loadCell(0, new CellData()).fg).to.equal(DEFAULT_ATTR_DATA.fg);
});
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(term.buffer.translateBufferLineToString(0, true)).to.equal('TEST');
expect(bufferService.buffer.translateBufferLineToString(0, true)).to.equal('TEST');
// Text color of 'TEST' should be default
expect(term.buffer.lines.get(0).loadCell(0, new CellData()).fg).to.equal(DEFAULT_ATTR_DATA.fg);
expect(bufferService.buffer.lines.get(0).loadCell(0, new CellData()).fg).to.equal(DEFAULT_ATTR_DATA.fg);
handler.parse('\x1b[?1049h\x1b[uTEST');
expect(term.buffer.translateBufferLineToString(1, true)).to.equal('TEST');
expect(bufferService.buffer.translateBufferLineToString(1, true)).to.equal('TEST');
// Text color of 'TEST' should be red
expect((term.buffer.lines.get(1).loadCell(0, new CellData()).getFgColor())).to.equal(1);
expect((bufferService.buffer.lines.get(1).loadCell(0, new CellData()).getFgColor())).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).loadCell(10, new CellData()).getBgColor()).to.equal(2);
expect(bufferService.buffer.lines.get(20).loadCell(10, new CellData()).getBgColor()).to.equal(2);
});
});