Merge branch 'master' into 682_url_selector

This commit is contained in:
Daniel Imms
2021-03-30 05:34:38 -07:00
committed by GitHub
42 changed files with 2829 additions and 1131 deletions
+1 -3
View File
@@ -156,9 +156,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
private _onTooltip(e: MouseEvent): void {
this._tooltipTimeout = undefined;
const zone = this._findZoneEventAt(e);
if (zone && zone.tooltipCallback) {
zone.tooltipCallback(e);
}
zone?.tooltipCallback(e);
}
private _onMouseDown(e: MouseEvent): void {
+244 -230
View File
@@ -55,22 +55,30 @@ describe('Terminal', () => {
// term.onData(() => done());
// term.handler('fake');
// });
it('should fire the onCursorMove event', (done) => {
term.onCursorMove(() => done());
term.writeSync('foo');
it('should fire the onCursorMove event', () => {
return new Promise(async r => {
term.onCursorMove(() => r());
await term.writeP('foo');
});
});
it('should fire the onLineFeed event', (done) => {
term.onLineFeed(() => done());
term.writeSync('\n');
it('should fire the onLineFeed event', () => {
return new Promise(async r => {
term.onLineFeed(() => r());
await term.writeP('\n');
});
});
it('should fire a scroll event when scrollback is created', (done) => {
term.onScroll(() => done());
term.writeSync('\n'.repeat(INIT_ROWS));
it('should fire a scroll event when scrollback is created', () => {
return new Promise(async r => {
term.onScroll(() => r());
await term.writeP('\n'.repeat(INIT_ROWS));
});
});
it('should fire a scroll event when scrollback is cleared', (done) => {
term.writeSync('\n'.repeat(INIT_ROWS));
term.onScroll(() => done());
term.clear();
it('should fire a scroll event when scrollback is cleared', () => {
return new Promise(async r => {
await term.writeP('\n'.repeat(INIT_ROWS));
term.onScroll(() => r());
term.clear();
});
});
it('should fire a key event after a keypress DOM event', (done) => {
term.onKey(e => {
@@ -177,10 +185,10 @@ describe('Terminal', () => {
assert.deepEqual(term.buffer.lines.get(i), term.buffer.getBlankLine(DEFAULT_ATTR_DATA));
}
});
it('should clear a buffer larger than rows', () => {
it('should clear a buffer larger than rows', async () => {
// Fill the buffer with dummy rows
for (let i = 0; i < term.rows * 2; i++) {
term.writeSync('test\n');
await term.writeP('test\n');
}
const promptLine = term.buffer.lines.get(term.buffer.ybase + term.buffer.y);
@@ -224,22 +232,24 @@ describe('Terminal', () => {
});
term.paste('\r\nfoo\nbar\r');
});
it('should respect bracketed paste mode', done => {
term.onData(e => {
assert.equal(e, '\x1b[200~foo\x1b[201~');
done();
it('should respect bracketed paste mode', () => {
return new Promise(async r => {
term.onData(e => {
assert.equal(e, '\x1b[200~foo\x1b[201~');
r();
});
await term.writeP('\x1b[?2004h');
term.paste('foo');
});
term.writeSync('\x1b[?2004h');
term.paste('foo');
});
});
describe('scroll', () => {
describe('scrollLines', () => {
let startYDisp: number;
beforeEach(() => {
beforeEach(async () => {
for (let i = 0; i < INIT_ROWS * 2; i++) {
term.writeSync('test\r\n');
await term.writeP('test\r\n');
}
startYDisp = INIT_ROWS + 1;
});
@@ -272,9 +282,9 @@ describe('Terminal', () => {
describe('scrollPages', () => {
let startYDisp: number;
beforeEach(() => {
beforeEach(async () => {
for (let i = 0; i < term.rows * 3; i++) {
term.writeSync('test\r\n');
await term.writeP('test\r\n');
}
startYDisp = (term.rows * 2) + 1;
});
@@ -295,9 +305,9 @@ describe('Terminal', () => {
});
describe('scrollToTop', () => {
beforeEach(() => {
beforeEach(async () => {
for (let i = 0; i < term.rows * 3; i++) {
term.writeSync('test\r\n');
await term.writeP('test\r\n');
}
});
it('should scroll to the top', () => {
@@ -309,9 +319,9 @@ describe('Terminal', () => {
describe('scrollToBottom', () => {
let startYDisp: number;
beforeEach(() => {
beforeEach(async () => {
for (let i = 0; i < term.rows * 3; i++) {
term.writeSync('test\r\n');
await term.writeP('test\r\n');
}
startYDisp = (term.rows * 2) + 1;
});
@@ -330,9 +340,9 @@ describe('Terminal', () => {
describe('scrollToLine', () => {
let startYDisp: number;
beforeEach(() => {
beforeEach(async () => {
for (let i = 0; i < term.rows * 3; i++) {
term.writeSync('test\r\n');
await term.writeP('test\r\n');
}
startYDisp = (term.rows * 2) + 1;
});
@@ -374,10 +384,10 @@ describe('Terminal', () => {
assert.equal(term.buffer.ydisp, term.buffer.ybase);
});
it('should not scroll down, when a custom keydown handler prevents the event', () => {
it('should not scroll down, when a custom keydown handler prevents the event', async () => {
// Add some output to the terminal
for (let i = 0; i < term.rows * 3; i++) {
term.writeSync('test\r\n');
await term.writeP('test\r\n');
}
const startYDisp = (term.rows * 2) + 1;
term.attachCustomKeyEventHandler(() => {
@@ -716,12 +726,12 @@ describe('Terminal', () => {
});
describe('unicode - surrogates', () => {
it('2 characters per cell', function (): void {
it('2 characters per cell', async function (): Promise<void> {
this.timeout(10000); // This is needed because istanbul patches code and slows it down
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.writeSync(high + String.fromCharCode(i));
await term.writeP(high + String.fromCharCode(i));
const tchar = term.buffer.lines.get(0)!.loadCell(0, cell);
assert.equal(tchar.getChars(), high + String.fromCharCode(i));
assert.equal(tchar.getChars().length, 2);
@@ -730,25 +740,26 @@ describe('Terminal', () => {
term.reset();
}
});
it('2 characters at last cell', () => {
it('2 characters at last cell', async () => {
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
term.writeSync(high + String.fromCharCode(i));
await term.writeP(high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars(), high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.buffer.x - 1, cell).getChars().length, 2);
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars(), '');
term.reset();
}
});
it('2 characters per cell over line end with autowrap', () => {
it('2 characters per cell over line end with autowrap', async function (): Promise<void> {
this.timeout(10000);
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
term.writeSync('a' + high + String.fromCharCode(i));
await term.writeP('a' + high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars(), 'a');
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars(), high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(1)!.loadCell(0, cell).getChars().length, 2);
@@ -756,17 +767,18 @@ describe('Terminal', () => {
term.reset();
}
});
it('2 characters per cell over line end without autowrap', () => {
it('2 characters per cell over line end without autowrap', async function (): Promise<void> {
this.timeout(10000);
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
term.writeSync('\x1b[?7l'); // Disable wraparound mode
await term.writeP('\x1b[?7l'); // Disable wraparound mode
const width = wcwidth((0xD800 - 0xD800) * 0x400 + i - 0xDC00 + 0x10000);
if (width !== 1) {
continue;
}
term.writeSync('a' + high + String.fromCharCode(i));
await term.writeP('a' + high + String.fromCharCode(i));
// auto wraparound mode should cut off the rest of the line
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars(), high + String.fromCharCode(i));
assert.equal(term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell).getChars().length, 2);
@@ -774,12 +786,12 @@ describe('Terminal', () => {
term.reset();
}
});
it('splitted surrogates', () => {
it('splitted surrogates', async function (): Promise<void> {
this.timeout(10000);
const high = String.fromCharCode(0xD800);
const cell = new CellData();
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.writeSync(high);
term.writeSync(String.fromCharCode(i));
await term.writeP(high + String.fromCharCode(i));
const tchar = term.buffer.lines.get(0)!.loadCell(0, cell);
assert.equal(tchar.getChars(), high + String.fromCharCode(i));
assert.equal(tchar.getChars().length, 2);
@@ -792,16 +804,16 @@ describe('Terminal', () => {
describe('unicode - combining characters', () => {
const cell = new CellData();
it('café', () => {
term.writeSync('cafe\u0301');
it('café', async () => {
await term.writeP('cafe\u0301');
term.buffer.lines.get(0)!.loadCell(3, cell);
assert.equal(cell.getChars(), 'e\u0301');
assert.equal(cell.getChars().length, 2);
assert.equal(cell.getWidth(), 1);
});
it('café - end of line', () => {
it('café - end of line', async () => {
term.buffer.x = term.cols - 1 - 3;
term.writeSync('cafe\u0301');
await term.writeP('cafe\u0301');
term.buffer.lines.get(0)!.loadCell(term.cols - 1, cell);
assert.equal(cell.getChars(), 'e\u0301');
assert.equal(cell.getChars().length, 2);
@@ -811,8 +823,8 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 0);
assert.equal(cell.getWidth(), 1);
});
it('multiple combined é', () => {
term.writeSync(Array(100).join('e\u0301'));
it('multiple combined é', async () => {
await term.writeP(Array(100).join('e\u0301'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
assert.equal(cell.getChars(), 'e\u0301');
@@ -824,8 +836,8 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 2);
assert.equal(cell.getWidth(), 1);
});
it('multiple surrogate with combined', () => {
term.writeSync(Array(100).join('\uD800\uDC00\u0301'));
it('multiple surrogate with combined', async () => {
await term.writeP(Array(100).join('\uD800\uDC00\u0301'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
assert.equal(cell.getChars(), '\uD800\uDC00\u0301');
@@ -841,19 +853,19 @@ describe('Terminal', () => {
describe('unicode - fullwidth characters', () => {
const cell = new CellData();
it('cursor movement even', () => {
it('cursor movement even', async () => {
assert.equal(term.buffer.x, 0);
term.writeSync('¥');
await term.writeP('¥');
assert.equal(term.buffer.x, 2);
});
it('cursor movement odd', () => {
it('cursor movement odd', async () => {
term.buffer.x = 1;
assert.equal(term.buffer.x, 1);
term.writeSync('¥');
await term.writeP('¥');
assert.equal(term.buffer.x, 3);
});
it('line of ¥ even', () => {
term.writeSync(Array(50).join('¥'));
it('line of ¥ even', async () => {
await term.writeP(Array(50).join('¥'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
if (i % 2) {
@@ -871,9 +883,9 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 1);
assert.equal(cell.getWidth(), 2);
});
it('line of ¥ odd', () => {
it('line of ¥ odd', async () => {
term.buffer.x = 1;
term.writeSync(Array(50).join('¥'));
await term.writeP(Array(50).join('¥'));
for (let i = 1; i < term.cols - 1; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
if (!(i % 2)) {
@@ -895,9 +907,9 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 1);
assert.equal(cell.getWidth(), 2);
});
it('line of ¥ with combining odd', () => {
it('line of ¥ with combining odd', async () => {
term.buffer.x = 1;
term.writeSync(Array(50).join('¥\u0301'));
await term.writeP(Array(50).join('¥\u0301'));
for (let i = 1; i < term.cols - 1; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
if (!(i % 2)) {
@@ -919,8 +931,8 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 2);
assert.equal(cell.getWidth(), 2);
});
it('line of ¥ with combining even', () => {
term.writeSync(Array(50).join('¥\u0301'));
it('line of ¥ with combining even', async () => {
await term.writeP(Array(50).join('¥\u0301'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
if (i % 2) {
@@ -938,9 +950,9 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 2);
assert.equal(cell.getWidth(), 2);
});
it('line of surrogate fullwidth with combining odd', () => {
it('line of surrogate fullwidth with combining odd', async () => {
term.buffer.x = 1;
term.writeSync(Array(50).join('\ud843\ude6d\u0301'));
await term.writeP(Array(50).join('\ud843\ude6d\u0301'));
for (let i = 1; i < term.cols - 1; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
if (!(i % 2)) {
@@ -962,8 +974,8 @@ describe('Terminal', () => {
assert.equal(cell.getChars().length, 3);
assert.equal(cell.getWidth(), 2);
});
it('line of surrogate fullwidth with combining even', () => {
term.writeSync(Array(50).join('\ud843\ude6d\u0301'));
it('line of surrogate fullwidth with combining even', async () => {
await term.writeP(Array(50).join('\ud843\ude6d\u0301'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0)!.loadCell(i, cell);
if (i % 2) {
@@ -985,24 +997,24 @@ describe('Terminal', () => {
describe('insert mode', () => {
const cell = new CellData();
it('halfwidth - all', () => {
term.writeSync(Array(9).join('0123456789').slice(-80));
it('halfwidth - all', async () => {
await term.writeP(Array(9).join('0123456789').slice(-80));
term.buffer.x = 10;
term.buffer.y = 0;
term.write('\x1b[4h');
term.writeSync('abcde');
await term.writeP('abcde');
assert.equal(term.buffer.lines.get(0)!.length, term.cols);
assert.equal(term.buffer.lines.get(0)!.loadCell(10, cell).getChars(), 'a');
assert.equal(term.buffer.lines.get(0)!.loadCell(14, cell).getChars(), 'e');
assert.equal(term.buffer.lines.get(0)!.loadCell(15, cell).getChars(), '0');
assert.equal(term.buffer.lines.get(0)!.loadCell(79, cell).getChars(), '4');
});
it('fullwidth - insert', () => {
term.writeSync(Array(9).join('0123456789').slice(-80));
it('fullwidth - insert', async () => {
await term.writeP(Array(9).join('0123456789').slice(-80));
term.buffer.x = 10;
term.buffer.y = 0;
term.write('\x1b[4h');
term.writeSync('¥¥¥');
await term.writeP('¥¥¥');
assert.equal(term.buffer.lines.get(0)!.length, term.cols);
assert.equal(term.buffer.lines.get(0)!.loadCell(10, cell).getChars(), '¥');
assert.equal(term.buffer.lines.get(0)!.loadCell(11, cell).getChars(), '');
@@ -1010,17 +1022,17 @@ describe('Terminal', () => {
assert.equal(term.buffer.lines.get(0)!.loadCell(15, cell).getChars(), '');
assert.equal(term.buffer.lines.get(0)!.loadCell(79, cell).getChars(), '3');
});
it('fullwidth - right border', () => {
term.writeSync(Array(41).join('¥'));
it('fullwidth - right border', async () => {
await term.writeP(Array(41).join('¥'));
term.buffer.x = 10;
term.buffer.y = 0;
term.write('\x1b[4h');
term.writeSync('a');
await term.writeP('a');
assert.equal(term.buffer.lines.get(0)!.length, term.cols);
assert.equal(term.buffer.lines.get(0)!.loadCell(10, cell).getChars(), 'a');
assert.equal(term.buffer.lines.get(0)!.loadCell(11, cell).getChars(), '¥');
assert.equal(term.buffer.lines.get(0)!.loadCell(79, cell).getChars(), ''); // fullwidth char got replaced
term.writeSync('b');
await term.writeP('b');
assert.equal(term.buffer.lines.get(0)!.length, term.cols);
assert.equal(term.buffer.lines.get(0)!.loadCell(11, cell).getChars(), 'b');
assert.equal(term.buffer.lines.get(0)!.loadCell(12, cell).getChars(), '¥');
@@ -1042,85 +1054,87 @@ describe('Terminal', () => {
linkifier.attachToDom({} as any, mouseZoneManager);
});
function assertLinkifiesInTerminal(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[], done: Mocha.Done): void {
terminal.writeSync(rowText);
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
linkifier.linkifyRows();
// Allow linkify to happen
setTimeout(() => {
assert.equal(mouseZoneManager.zones.length, links.length);
links.forEach((l, i) => {
assert.equal(mouseZoneManager.zones[i].x1, l.x1 + 1);
assert.equal(mouseZoneManager.zones[i].x2, l.x2 + 1);
assert.equal(mouseZoneManager.zones[i].y1, l.y1 + 1);
assert.equal(mouseZoneManager.zones[i].y2, l.y2 + 1);
});
done();
}, 0);
function assertLinkifiesInTerminal(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[]): Promise<void> {
return new Promise(async r => {
await terminal.writeP(rowText);
linkifier.registerLinkMatcher(linkMatcherRegex, () => {});
linkifier.linkifyRows();
// Allow linkify to happen
setTimeout(() => {
assert.equal(mouseZoneManager.zones.length, links.length);
links.forEach((l, i) => {
assert.equal(mouseZoneManager.zones[i].x1, l.x1 + 1);
assert.equal(mouseZoneManager.zones[i].x2, l.x2 + 1);
assert.equal(mouseZoneManager.zones[i].y1, l.y1 + 1);
assert.equal(mouseZoneManager.zones[i].y2, l.y2 + 1);
});
r();
}, 0);
});
}
describe('unicode before the match', () => {
it('combining - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('e\u0301e\u0301e\u0301 foo', /foo/, [{x1: 4, x2: 7, y1: 0, y2: 0}], done);
it('combining - match within one line', () => {
return assertLinkifiesInTerminal('e\u0301e\u0301e\u0301 foo', /foo/, [{x1: 4, x2: 7, y1: 0, y2: 0}]);
});
it('combining - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('e\u0301e\u0301e\u0301 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}], done);
it('combining - match over two lines', () => {
return assertLinkifiesInTerminal('e\u0301e\u0301e\u0301 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}]);
});
it('surrogate - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('𝄞𝄞𝄞 foo', /foo/, [{x1: 4, x2: 7, y1: 0, y2: 0}], done);
it('surrogate - match within one line', () => {
return assertLinkifiesInTerminal('𝄞𝄞𝄞 foo', /foo/, [{x1: 4, x2: 7, y1: 0, y2: 0}]);
});
it('surrogate - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('𝄞𝄞𝄞 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}], done);
it('surrogate - match over two lines', () => {
return assertLinkifiesInTerminal('𝄞𝄞𝄞 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}]);
});
it('combining surrogate - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('𓂀\u0301𓂀\u0301𓂀\u0301 foo', /foo/, [{x1: 4, x2: 7, y1: 0, y2: 0}], done);
it('combining surrogate - match within one line', () => {
return assertLinkifiesInTerminal('𓂀\u0301𓂀\u0301𓂀\u0301 foo', /foo/, [{x1: 4, x2: 7, y1: 0, y2: 0}]);
});
it('combining surrogate - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('𓂀\u0301𓂀\u0301𓂀\u0301 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}], done);
it('combining surrogate - match over two lines', () => {
return assertLinkifiesInTerminal('𓂀\u0301𓂀\u0301𓂀\u0301 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}]);
});
it('fullwidth - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('12 foo', /foo/, [{x1: 5, x2: 8, y1: 0, y2: 0}], done);
it('fullwidth - match within one line', () => {
return assertLinkifiesInTerminal('12 foo', /foo/, [{x1: 5, x2: 8, y1: 0, y2: 0}]);
});
it('fullwidth - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('12 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}], done);
it('fullwidth - match over two lines', () => {
return assertLinkifiesInTerminal('12 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}]);
});
it('combining fullwidth - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('¥\u0301¥\u0301 foo', /foo/, [{x1: 5, x2: 8, y1: 0, y2: 0}], done);
it('combining fullwidth - match within one line', () => {
return assertLinkifiesInTerminal('¥\u0301¥\u0301 foo', /foo/, [{x1: 5, x2: 8, y1: 0, y2: 0}]);
});
it('combining fullwidth - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('¥\u0301¥\u0301 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}], done);
it('combining fullwidth - match over two lines', () => {
return assertLinkifiesInTerminal('¥\u0301¥\u0301 foo', /foo/, [{x1: 8, x2: 1, y1: 0, y2: 1}]);
});
});
describe('unicode within the match', () => {
it('combining - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('test cafe\u0301', /cafe\u0301/, [{x1: 5, x2: 9, y1: 0, y2: 0}], done);
it('combining - match within one line', () => {
return assertLinkifiesInTerminal('test cafe\u0301', /cafe\u0301/, [{x1: 5, x2: 9, y1: 0, y2: 0}]);
});
it('combining - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('testtest cafe\u0301', /cafe\u0301/, [{x1: 9, x2: 3, y1: 0, y2: 1}], done);
it('combining - match over two lines', () => {
return assertLinkifiesInTerminal('testtest cafe\u0301', /cafe\u0301/, [{x1: 9, x2: 3, y1: 0, y2: 1}]);
});
it('surrogate - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('test a𝄞b', /a𝄞b/, [{x1: 5, x2: 8, y1: 0, y2: 0}], done);
it('surrogate - match within one line', () => {
return assertLinkifiesInTerminal('test a𝄞b', /a𝄞b/, [{x1: 5, x2: 8, y1: 0, y2: 0}]);
});
it('surrogate - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('testtest a𝄞b', /a𝄞b/, [{x1: 9, x2: 2, y1: 0, y2: 1}], done);
it('surrogate - match over two lines', () => {
return assertLinkifiesInTerminal('testtest a𝄞b', /a𝄞b/, [{x1: 9, x2: 2, y1: 0, y2: 1}]);
});
it('combining surrogate - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('test a𓂀\u0301b', /a𓂀\u0301b/, [{x1: 5, x2: 8, y1: 0, y2: 0}], done);
it('combining surrogate - match within one line', () => {
return assertLinkifiesInTerminal('test a𓂀\u0301b', /a𓂀\u0301b/, [{x1: 5, x2: 8, y1: 0, y2: 0}]);
});
it('combining surrogate - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('testtest a𓂀\u0301b', /a𓂀\u0301b/, [{x1: 9, x2: 2, y1: 0, y2: 1}], done);
it('combining surrogate - match over two lines', () => {
return assertLinkifiesInTerminal('testtest a𓂀\u0301b', /a𓂀\u0301b/, [{x1: 9, x2: 2, y1: 0, y2: 1}]);
});
it('fullwidth - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('test a1b', /a1b/, [{x1: 5, x2: 9, y1: 0, y2: 0}], done);
it('fullwidth - match within one line', () => {
return assertLinkifiesInTerminal('test a1b', /a1b/, [{x1: 5, x2: 9, y1: 0, y2: 0}]);
});
it('fullwidth - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('testtest a1b', /a1b/, [{x1: 9, x2: 3, y1: 0, y2: 1}], done);
it('fullwidth - match over two lines', () => {
return assertLinkifiesInTerminal('testtest a1b', /a1b/, [{x1: 9, x2: 3, y1: 0, y2: 1}]);
});
it('combining fullwidth - match within one line', function(done: () => void): void {
assertLinkifiesInTerminal('test a¥\u0301b', /a¥\u0301b/, [{x1: 5, x2: 9, y1: 0, y2: 0}], done);
it('combining fullwidth - match within one line', () => {
return assertLinkifiesInTerminal('test a¥\u0301b', /a¥\u0301b/, [{x1: 5, x2: 9, y1: 0, y2: 0}]);
});
it('combining fullwidth - match over two lines', function(done: () => void): void {
assertLinkifiesInTerminal('testtest a¥\u0301b', /a¥\u0301b/, [{x1: 9, x2: 3, y1: 0, y2: 1}], done);
it('combining fullwidth - match over two lines', () => {
return assertLinkifiesInTerminal('testtest a¥\u0301b', /a¥\u0301b/, [{x1: 9, x2: 3, y1: 0, y2: 1}]);
});
});
});
@@ -1132,9 +1146,9 @@ describe('Terminal', () => {
terminal = new TestTerminal({rows: 5, cols: 10, scrollback: 5});
});
it('multiline ascii', () => {
it('multiline ascii', async () => {
const input = 'This is ASCII text spanning multiple lines.';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 0; i < input.length; ++i) {
@@ -1143,9 +1157,9 @@ describe('Terminal', () => {
}
});
it('combining e\u0301 in a sentence', () => {
it('combining e\u0301 in a sentence', async () => {
const input = 'Sitting in the cafe\u0301 drinking coffee.';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 0; i < 19; ++i) {
@@ -1163,9 +1177,9 @@ describe('Terminal', () => {
}
});
it('multiline combining e\u0301', () => {
it('multiline combining e\u0301', async () => {
const input = 'e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301e\u0301';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
// every buffer cell index contains 2 string indices
@@ -1175,9 +1189,9 @@ describe('Terminal', () => {
}
});
it('surrogate char in a sentence', () => {
it('surrogate char in a sentence', async () => {
const input = 'The 𝄞 is a clef widely used in modern notation.';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 0; i < 5; ++i) {
@@ -1195,9 +1209,9 @@ describe('Terminal', () => {
}
});
it('multiline surrogate char', () => {
it('multiline surrogate char', async () => {
const input = '𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞𝄞';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
// every buffer cell index contains 2 string indices
@@ -1207,10 +1221,10 @@ describe('Terminal', () => {
}
});
it('surrogate char with combining', () => {
it('surrogate char with combining', async () => {
// eye of Ra with acute accent - string length of 3
const input = '𓂀\u0301 - the eye hiroglyph with an acute accent.';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
// index 0..2 should map to 0
@@ -1222,9 +1236,9 @@ describe('Terminal', () => {
}
});
it('multiline surrogate with combining', () => {
it('multiline surrogate with combining', async () => {
const input = '𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301𓂀\u0301';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
// every buffer cell index contains 3 string indices
@@ -1234,9 +1248,9 @@ describe('Terminal', () => {
}
});
it('fullwidth chars', () => {
it('fullwidth chars', async () => {
const input = 'These 123 are some fat numbers.';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 0; i < 6; ++i) {
@@ -1253,9 +1267,9 @@ describe('Terminal', () => {
}
});
it('multiline fullwidth chars', () => {
it('multiline fullwidth chars', async () => {
const input = '12345678901234567890';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 9; i < input.length; ++i) {
@@ -1264,9 +1278,9 @@ describe('Terminal', () => {
}
});
it('fullwidth combining with emoji - match emoji cell', () => {
it('fullwidth combining with emoji - match emoji cell', async () => {
const input = 'Lots of ¥\u0301 make me 😃.';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
const stringIndex = s.match(/😃/)!.index!;
@@ -1274,14 +1288,14 @@ describe('Terminal', () => {
assert(terminal.buffer.lines.get(bufferIndex[0])!.loadCell(bufferIndex[1], new CellData()).getChars(), '😃');
});
it('multiline fullwidth chars with offset 1 (currently tests for broken behavior)', () => {
it('multiline fullwidth chars with offset 1 (currently tests for broken behavior)', async () => {
const input = 'a12345678901234567890';
// the 'a' at the beginning moves all fullwidth chars one to the right
// now the end of the line contains a dangling empty cell since
// the next fullwidth char has to wrap early
// the dangling last cell is wrongly added in the string
// --> fixable after resolving #1685
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 10; i < input.length; ++i) {
@@ -1291,9 +1305,9 @@ describe('Terminal', () => {
}
});
it('test fully wrapped buffer up to last char', () => {
it('test fully wrapped buffer up to last char', async () => {
const input = Array(6).join('1234567890');
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 0; i < input.length; ++i) {
@@ -1302,10 +1316,10 @@ describe('Terminal', () => {
}
});
it('test fully wrapped buffer up to last char with full width odd', () => {
it('test fully wrapped buffer up to last char with full width odd', async () => {
const input = 'a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301'
+ 'a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301a¥\u0301';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 0; i < input.length; ++i) {
@@ -1320,16 +1334,16 @@ describe('Terminal', () => {
}
});
it('should handle \t in lines correctly', () => {
it('should handle \t in lines correctly', async () => {
const input = '\thttps://google.de';
terminal.writeSync(input);
await terminal.writeP(input);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(s, Array(terminal.optionsService.options.tabStopWidth + 1).join(' ') + 'https://google.de');
});
});
describe('BufferStringIterator', function(): void {
it('iterator does not overflow buffer limits', function(): void {
it('iterator does not overflow buffer limits', async () => {
const terminal = new TestTerminal({rows: 5, cols: 10, scrollback: 5});
const data = [
'aaaaaaaaaa',
@@ -1343,7 +1357,7 @@ describe('Terminal', () => {
'aaaaaaaaaa',
'aaaaaaaaaa'
];
terminal.writeSync(data.join(''));
await terminal.writeP(data.join(''));
// brute force test with insane values
assert.doesNotThrow(() => {
for (let overscan = 0; overscan < 20; ++overscan) {
@@ -1361,7 +1375,7 @@ describe('Terminal', () => {
});
describe('Windows Mode', () => {
it('should mark lines as wrapped when the line ends in a non-null character after a LF', () => {
it('should mark lines as wrapped when the line ends in a non-null character after a LF', async () => {
const data = [
'aaaaaaaaaa\n\r', // cannot wrap as it's the first
'aaaaaaaaa\n\r', // wrapped (windows mode only)
@@ -1369,19 +1383,19 @@ describe('Terminal', () => {
];
const normalTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: false});
normalTerminal.writeSync(data.join(''));
await normalTerminal.writeP(data.join(''));
assert.equal(normalTerminal.buffer.lines.get(0)!.isWrapped, false);
assert.equal(normalTerminal.buffer.lines.get(1)!.isWrapped, false);
assert.equal(normalTerminal.buffer.lines.get(2)!.isWrapped, false);
const windowsModeTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: true});
windowsModeTerminal.writeSync(data.join(''));
await windowsModeTerminal.writeP(data.join(''));
assert.equal(windowsModeTerminal.buffer.lines.get(0)!.isWrapped, false);
assert.equal(windowsModeTerminal.buffer.lines.get(1)!.isWrapped, true, 'This line should wrap in Windows mode as the previous line ends in a non-null character');
assert.equal(windowsModeTerminal.buffer.lines.get(2)!.isWrapped, false);
});
it('should mark lines as wrapped when the line ends in a non-null character after a CUP', () => {
it('should mark lines as wrapped when the line ends in a non-null character after a CUP', async () => {
const data = [
'aaaaaaaaaa\x1b[2;1H', // cannot wrap as it's the first
'aaaaaaaaa\x1b[3;1H', // wrapped (windows mode only)
@@ -1389,22 +1403,22 @@ describe('Terminal', () => {
];
const normalTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: false});
normalTerminal.writeSync(data.join(''));
await normalTerminal.writeP(data.join(''));
assert.equal(normalTerminal.buffer.lines.get(0)!.isWrapped, false);
assert.equal(normalTerminal.buffer.lines.get(1)!.isWrapped, false);
assert.equal(normalTerminal.buffer.lines.get(2)!.isWrapped, false);
const windowsModeTerminal = new TestTerminal({rows: 5, cols: 10, windowsMode: true});
windowsModeTerminal.writeSync(data.join(''));
await windowsModeTerminal.writeP(data.join(''));
assert.equal(windowsModeTerminal.buffer.lines.get(0)!.isWrapped, false);
assert.equal(windowsModeTerminal.buffer.lines.get(1)!.isWrapped, true, 'This line should wrap in Windows mode as the previous line ends in a non-null character');
assert.equal(windowsModeTerminal.buffer.lines.get(2)!.isWrapped, false);
});
});
it('convertEol setting', function(): void {
it('convertEol setting', async () => {
// not converting
const termNotConverting = new TestTerminal({cols: 15, rows: 10});
termNotConverting.writeSync('Hello\nWorld');
await termNotConverting.writeP('Hello\nWorld');
assert.equal(termNotConverting.buffer.lines.get(0)!.translateToString(false), 'Hello ');
assert.equal(termNotConverting.buffer.lines.get(1)!.translateToString(false), ' World ');
assert.equal(termNotConverting.buffer.lines.get(0)!.translateToString(true), 'Hello');
@@ -1412,7 +1426,7 @@ describe('Terminal', () => {
// converting
const termConverting = new TestTerminal({cols: 15, rows: 10, convertEol: true});
termConverting.writeSync('Hello\nWorld');
await termConverting.writeP('Hello\nWorld');
assert.equal(termConverting.buffer.lines.get(0)!.translateToString(false), 'Hello ');
assert.equal(termConverting.buffer.lines.get(1)!.translateToString(false), 'World ');
assert.equal(termConverting.buffer.lines.get(0)!.translateToString(true), 'Hello');
@@ -1433,54 +1447,54 @@ describe('Terminal', () => {
beforeEach(() => {
term = new TestTerminal({cols: 5, rows: 5, scrollback: 1});
});
it('SL (scrollLeft)', () => {
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[ @');
it('SL (scrollLeft)', async () => {
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[ @');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '2345', '2345', '2345', '2345', '2345']);
term.writeSync('\x1b[0 @');
await term.writeP('\x1b[0 @');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '345', '345', '345', '345', '345']);
term.writeSync('\x1b[2 @');
await term.writeP('\x1b[2 @');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '5', '5', '5', '5', '5']);
});
it('SR (scrollRight)', () => {
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[ A');
it('SR (scrollRight)', async () => {
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[ A');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', ' 1234', ' 1234', ' 1234', ' 1234', ' 1234']);
term.writeSync('\x1b[0 A');
await term.writeP('\x1b[0 A');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', ' 123', ' 123', ' 123', ' 123', ' 123']);
term.writeSync('\x1b[2 A');
await term.writeP('\x1b[2 A');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', ' 1', ' 1', ' 1', ' 1', ' 1']);
});
it('insertColumns (DECIC)', () => {
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[3;3H');
term.writeSync('\x1b[\'}');
it('insertColumns (DECIC)', async () => {
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[3;3H');
await term.writeP('\x1b[\'}');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '12 34', '12 34', '12 34', '12 34', '12 34']);
term.reset();
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[3;3H');
term.writeSync('\x1b[1\'}');
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[3;3H');
await term.writeP('\x1b[1\'}');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '12 34', '12 34', '12 34', '12 34', '12 34']);
term.reset();
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[3;3H');
term.writeSync('\x1b[2\'}');
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[3;3H');
await term.writeP('\x1b[2\'}');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '12 3', '12 3', '12 3', '12 3', '12 3']);
});
it('deleteColumns (DECDC)', () => {
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[3;3H');
term.writeSync('\x1b[\'~');
it('deleteColumns (DECDC)', async () => {
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[3;3H');
await term.writeP('\x1b[\'~');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '1245', '1245', '1245', '1245', '1245']);
term.reset();
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[3;3H');
term.writeSync('\x1b[1\'~');
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[3;3H');
await term.writeP('\x1b[1\'~');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '1245', '1245', '1245', '1245', '1245']);
term.reset();
term.writeSync('12345'.repeat(6));
term.writeSync('\x1b[3;3H');
term.writeSync('\x1b[2\'~');
await term.writeP('12345'.repeat(6));
await term.writeP('\x1b[3;3H');
await term.writeP('\x1b[2\'~');
assert.deepEqual(getLines(term, term.rows + 1), ['12345', '125', '125', '125', '125', '125']);
});
});
@@ -1493,41 +1507,41 @@ describe('Terminal', () => {
});
describe('reverseWraparound set', () => {
it('should not reverse outside of scroll margins', () => {
it('should not reverse outside of scroll margins', async () => {
// prepare buffer content
term.writeSync('#####abcdefghijklmnopqrstuvwxy');
await term.writeP('#####abcdefghijklmnopqrstuvwxy');
assert.deepEqual(getLines(term, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', 'uvwxy']);
assert.equal(term.buffer.ydisp, 1);
assert.equal(term.buffer.x, 5);
assert.equal(term.buffer.y, 4);
term.writeSync(ttyBS.repeat(100));
await term.writeP(ttyBS.repeat(100));
assert.deepEqual(getLines(term, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', ' y']);
term.writeSync('\x1b[?45h');
term.writeSync('uvwxy');
await term.writeP('\x1b[?45h');
await term.writeP('uvwxy');
// set top/bottom to 1/3 (0-based)
term.writeSync('\x1b[2;4r');
await term.writeP('\x1b[2;4r');
// place cursor below scroll bottom
term.buffer.x = 5;
term.buffer.y = 4;
term.writeSync(ttyBS.repeat(100));
await term.writeP(ttyBS.repeat(100));
assert.deepEqual(getLines(term, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', ' ']);
term.writeSync('uvwxy');
await term.writeP('uvwxy');
// place cursor within scroll margins
term.buffer.x = 5;
term.buffer.y = 3;
term.writeSync(ttyBS.repeat(100));
await term.writeP(ttyBS.repeat(100));
assert.deepEqual(getLines(term, 6), ['#####', 'abcde', ' ', ' ', ' ', 'uvwxy']);
assert.equal(term.buffer.x, 0);
assert.equal(term.buffer.y, term.buffer.scrollTop); // stops at 0, scrollTop
term.writeSync('fghijklmnopqrst');
await term.writeP('fghijklmnopqrst');
// place cursor above scroll top
term.buffer.x = 5;
term.buffer.y = 0;
term.writeSync(ttyBS.repeat(100));
await term.writeP(ttyBS.repeat(100));
assert.deepEqual(getLines(term, 6), ['#####', ' ', 'fghij', 'klmno', 'pqrst', 'uvwxy']);
});
});
@@ -1541,22 +1555,22 @@ describe('Terminal', () => {
let markers: IMarker[];
let disposeStack: IMarker[];
let term: TestTerminal;
beforeEach(() => {
beforeEach(async () => {
term = new TestTerminal({});
markers = [];
disposeStack = [];
term.optionsService.setOption('scrollback', 1);
term.resize(10, 5);
markers.push(term.buffers.active.addMarker(term.buffers.active.y));
term.writeSync('\x1b[r0\r\n');
await term.writeP('\x1b[r0\r\n');
markers.push(term.buffers.active.addMarker(term.buffers.active.y));
term.writeSync('1\r\n');
await term.writeP('1\r\n');
markers.push(term.buffers.active.addMarker(term.buffers.active.y));
term.writeSync('2\r\n');
await term.writeP('2\r\n');
markers.push(term.buffers.active.addMarker(term.buffers.active.y));
term.writeSync('3\r\n');
await term.writeP('3\r\n');
markers.push(term.buffers.active.addMarker(term.buffers.active.y));
term.writeSync('4');
await term.writeP('4');
for (let i = 0; i < markers.length; ++i) {
const marker = markers[i];
marker.onDispose(() => disposeStack.push(marker));
@@ -1565,15 +1579,15 @@ describe('Terminal', () => {
it('initial', () => {
assert.deepEqual(markers.map(m => m.line), [0, 1, 2, 3, 4]);
});
it('should dispose on normal trim off the top', () => {
it('should dispose on normal trim off the top', async () => {
// moves top line into scrollback
term.writeSync('\n');
await term.writeP('\n');
assert.deepEqual(disposeStack, []);
// trims first marker
term.writeSync('\n');
await term.writeP('\n');
assert.deepEqual(disposeStack, [markers[0]]);
// trims second marker
term.writeSync('\n');
await term.writeP('\n');
assert.deepEqual(disposeStack, [markers[0], markers[1]]);
// trimmed marker objs should be disposed
assert.deepEqual(disposeStack.map(el => el.isDisposed), [true, true]);
@@ -1581,14 +1595,14 @@ describe('Terminal', () => {
// trimmed markers should contain line -1
assert.deepEqual(disposeStack.map(el => el.line), [-1, -1]);
});
it('should dispose on DL', () => {
term.writeSync('\x1b[3;1H'); // move cursor to 0, 2
term.writeSync('\x1b[2M'); // delete 2 lines
it('should dispose on DL', async () => {
await term.writeP('\x1b[3;1H'); // move cursor to 0, 2
await term.writeP('\x1b[2M'); // delete 2 lines
assert.deepEqual(disposeStack, [markers[2], markers[3]]);
});
it('should dispose on IL', () => {
term.writeSync('\x1b[3;1H'); // move cursor to 0, 2
term.writeSync('\x1b[2L'); // insert 2 lines
it('should dispose on IL', async () => {
await term.writeP('\x1b[3;1H'); // move cursor to 0, 2
await term.writeP('\x1b[2L'); // insert 2 lines
assert.deepEqual(disposeStack, [markers[4], markers[3]]);
assert.deepEqual(markers.map(el => el.line), [0, 1, 4, -1, -1]);
});
+3 -3
View File
@@ -162,11 +162,11 @@ export class Terminal extends CoreTerminal implements ITerminal {
private _changeAnsiColor(event: IAnsiColorChangeEvent): void {
if (!this._colorManager) { return; }
event.colors.forEach(ansiColor => {
for (const ansiColor of event.colors) {
const color = rgba.toColor(ansiColor.red, ansiColor.green, ansiColor.blue);
this._colorManager!.colors.ansi[ansiColor.colorIndex] = color;
});
}
this._renderService?.setColors(this._colorManager!.colors);
this.viewport?.onThemeChange(this._colorManager!.colors);
@@ -836,7 +836,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
* Change the cursor style for different selection modes
*/
public updateCursorStyle(ev: KeyboardEvent): void {
if (this._selectionService && this._selectionService.shouldColumnSelect(ev)) {
if (this._selectionService?.shouldColumnSelect(ev)) {
this.element!.classList.add('column-select');
} else {
this.element!.classList.remove('column-select');
+1 -1
View File
@@ -74,7 +74,7 @@ describe('Escape Sequence Files', function(): void {
let content = '';
const OSC_CODE = 12345;
await new Promise(resolve => {
customHandler = term.addOscHandler(OSC_CODE, () => {
customHandler = term.registerOscHandler(OSC_CODE, () => {
// grab terminal viewport content
content = terminalToString(term);
resolve();
+7 -4
View File
@@ -21,6 +21,9 @@ export class TestTerminal extends Terminal {
public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; }
public keyDown(ev: any): boolean | undefined { return this._keyDown(ev); }
public keyPress(ev: any): boolean { return this._keyPress(ev); }
public writeP(data: string | Uint8Array): Promise<void> {
return new Promise(r => this.write(data, r));
}
}
export class MockTerminal implements ITerminal {
@@ -75,16 +78,16 @@ export class MockTerminal implements ITerminal {
public attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void {
throw new Error('Method not implemented.');
}
public addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable {
public registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable {
public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable {
public registerEscHandler(id: IFunctionIdentifier, handler: () => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
public registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable {
throw new Error('Method not implemented.');
}
public registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => boolean | void, options?: ILinkMatcherOptions): number {
+4 -4
View File
@@ -52,10 +52,10 @@ export interface IPublicTerminal extends IDisposable {
resize(columns: number, rows: number): void;
open(parent: HTMLElement): void;
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;
addCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean): IDisposable;
addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean): IDisposable;
addEscHandler(id: IFunctionIdentifier, callback: () => boolean): IDisposable;
addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable;
registerCsiHandler(id: IFunctionIdentifier, callback: (params: IParams) => boolean | Promise<boolean>): IDisposable;
registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: IParams) => boolean | Promise<boolean>): IDisposable;
registerEscHandler(id: IFunctionIdentifier, callback: () => boolean | Promise<boolean>): IDisposable;
registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable;
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number;
deregisterLinkMatcher(matcherId: number): void;
registerLinkProvider(linkProvider: ILinkProvider): IDisposable;
+3 -2
View File
@@ -222,8 +222,9 @@ export class CompositionHelper {
const compositionViewBounds = this._compositionView.getBoundingClientRect();
this._textarea.style.left = cursorLeft + 'px';
this._textarea.style.top = cursorTop + 'px';
this._textarea.style.width = compositionViewBounds.width + 'px';
this._textarea.style.height = compositionViewBounds.height + 'px';
// Ensure the text area is at least 1x1, otherwise certain IMEs may break
this._textarea.style.width = Math.max(compositionViewBounds.width, 1) + 'px';
this._textarea.style.height = Math.max(compositionViewBounds.height, 1) + 'px';
this._textarea.style.lineHeight = compositionViewBounds.height + 'px';
}
+12 -12
View File
@@ -292,28 +292,28 @@ class BufferLineApiView implements IBufferLineApi {
class ParserApi implements IParser {
constructor(private _core: ITerminal) { }
public registerCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable {
return this._core.addCsiHandler(id, (params: IParams) => callback(params.toArray()));
public registerCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean | Promise<boolean>): IDisposable {
return this._core.registerCsiHandler(id, (params: IParams) => callback(params.toArray()));
}
public addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean): IDisposable {
public addCsiHandler(id: IFunctionIdentifier, callback: (params: (number | number[])[]) => boolean | Promise<boolean>): IDisposable {
return this.registerCsiHandler(id, callback);
}
public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable {
return this._core.addDcsHandler(id, (data: string, params: IParams) => callback(data, params.toArray()));
public registerDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean | Promise<boolean>): IDisposable {
return this._core.registerDcsHandler(id, (data: string, params: IParams) => callback(data, params.toArray()));
}
public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean): IDisposable {
public addDcsHandler(id: IFunctionIdentifier, callback: (data: string, param: (number | number[])[]) => boolean | Promise<boolean>): IDisposable {
return this.registerDcsHandler(id, callback);
}
public registerEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable {
return this._core.addEscHandler(id, handler);
public registerEscHandler(id: IFunctionIdentifier, handler: () => boolean | Promise<boolean>): IDisposable {
return this._core.registerEscHandler(id, handler);
}
public addEscHandler(id: IFunctionIdentifier, handler: () => boolean): IDisposable {
public addEscHandler(id: IFunctionIdentifier, handler: () => boolean | Promise<boolean>): IDisposable {
return this.registerEscHandler(id, handler);
}
public registerOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
return this._core.addOscHandler(ident, callback);
public registerOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable {
return this._core.registerOscHandler(ident, callback);
}
public addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable {
public addOscHandler(ident: number, callback: (data: string) => boolean | Promise<boolean>): IDisposable {
return this.registerOscHandler(ident, callback);
}
}