Merge branch 'master' into strikethrough
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@ export function clone<T>(val: T, depth: number = 5): T {
|
||||
|
||||
for (const key in val) {
|
||||
// Recursively clone eack item unless we're at the maximum depth
|
||||
clonedObject[key] = depth <= 1 ? val[key] : (val[key] ? clone(val[key], depth - 1) : val[key]);
|
||||
clonedObject[key] = depth <= 1 ? val[key] : (val[key] && clone(val[key], depth - 1));
|
||||
}
|
||||
|
||||
return clonedObject as T;
|
||||
|
||||
@@ -125,6 +125,10 @@ export abstract class CoreTerminal extends Disposable implements ICoreTerminal {
|
||||
this._onScroll.fire({ position: this._bufferService.buffer.ydisp, source: ScrollSource.TERMINAL });
|
||||
this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop, this._bufferService.buffer.scrollBottom);
|
||||
}));
|
||||
this.register(this._inputHandler.onScroll(event => {
|
||||
this._onScroll.fire({ position: this._bufferService.buffer.ydisp, source: ScrollSource.TERMINAL });
|
||||
this._dirtyRowService.markRangeDirty(this._bufferService.buffer.scrollTop, this._bufferService.buffer.scrollBottom);
|
||||
}));
|
||||
|
||||
// Setup WriteBuffer
|
||||
this._writeBuffer = new WriteBuffer((data, promiseResult) => this._inputHandler.parse(data, promiseResult));
|
||||
|
||||
@@ -77,7 +77,7 @@ describe('InputHandler', () => {
|
||||
optionsService.options.scrollback = 1;
|
||||
bufferService.reset();
|
||||
});
|
||||
it('SL (scrollLeft)', async () => {
|
||||
it('SL (scrollLeft)', () => {
|
||||
inputHandler.parseP('12345'.repeat(6));
|
||||
inputHandler.parseP('\x1b[ @');
|
||||
assert.deepEqual(getLines(bufferService, 6), ['12345', '2345', '2345', '2345', '2345', '2345']);
|
||||
@@ -86,7 +86,7 @@ describe('InputHandler', () => {
|
||||
inputHandler.parseP('\x1b[2 @');
|
||||
assert.deepEqual(getLines(bufferService, 6), ['12345', '5', '5', '5', '5', '5']);
|
||||
});
|
||||
it('SR (scrollRight)', async () => {
|
||||
it('SR (scrollRight)', () => {
|
||||
inputHandler.parseP('12345'.repeat(6));
|
||||
inputHandler.parseP('\x1b[ A');
|
||||
assert.deepEqual(getLines(bufferService, 6), ['12345', ' 1234', ' 1234', ' 1234', ' 1234', ' 1234']);
|
||||
@@ -95,7 +95,7 @@ describe('InputHandler', () => {
|
||||
inputHandler.parseP('\x1b[2 A');
|
||||
assert.deepEqual(getLines(bufferService, 6), ['12345', ' 1', ' 1', ' 1', ' 1', ' 1']);
|
||||
});
|
||||
it('insertColumns (DECIC)', async () => {
|
||||
it('insertColumns (DECIC)', () => {
|
||||
inputHandler.parseP('12345'.repeat(6));
|
||||
inputHandler.parseP('\x1b[3;3H');
|
||||
inputHandler.parseP('\x1b[\'}');
|
||||
@@ -111,7 +111,7 @@ describe('InputHandler', () => {
|
||||
inputHandler.parseP('\x1b[2\'}');
|
||||
assert.deepEqual(getLines(bufferService, 6), ['12345', '12 3', '12 3', '12 3', '12 3', '12 3']);
|
||||
});
|
||||
it('deleteColumns (DECDC)', async () => {
|
||||
it('deleteColumns (DECDC)', () => {
|
||||
inputHandler.parseP('12345'.repeat(6));
|
||||
inputHandler.parseP('\x1b[3;3H');
|
||||
inputHandler.parseP('\x1b[\'~');
|
||||
@@ -137,7 +137,7 @@ describe('InputHandler', () => {
|
||||
bufferService.reset();
|
||||
});
|
||||
describe('reverseWraparound set', () => {
|
||||
it('should not reverse outside of scroll margins', async () => {
|
||||
it('should not reverse outside of scroll margins', () => {
|
||||
// prepare buffer content
|
||||
inputHandler.parseP('#####abcdefghijklmnopqrstuvwxy');
|
||||
assert.deepEqual(getLines(bufferService, 6), ['#####', 'abcde', 'fghij', 'klmno', 'pqrst', 'uvwxy']);
|
||||
@@ -1919,6 +1919,92 @@ describe('InputHandler', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// issue #3362 and #2979
|
||||
describe('EL/ED cursor at buffer.cols', () => {
|
||||
beforeEach(() => {
|
||||
bufferService.resize(10, 5);
|
||||
});
|
||||
describe('cursor should stay at cols / does not overflow', () => {
|
||||
it('EL0', async () => {
|
||||
await inputHandler.parseP('##########\x1b[0K');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['#'.repeat(10), '', '', '', '']);
|
||||
});
|
||||
it('EL1', async () => {
|
||||
await inputHandler.parseP('##########\x1b[1K');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
|
||||
});
|
||||
it('EL2', async () => {
|
||||
await inputHandler.parseP('##########\x1b[2K');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
|
||||
});
|
||||
it('ED0', async () => {
|
||||
await inputHandler.parseP('##########\x1b[0J');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['#'.repeat(10), '', '', '', '']);
|
||||
});
|
||||
it('ED1', async () => {
|
||||
await inputHandler.parseP('##########\x1b[1J');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
|
||||
});
|
||||
it('ED2', async () => {
|
||||
await inputHandler.parseP('##########\x1b[2J');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['', '', '', '', '']);
|
||||
});
|
||||
it('ED3', async () => {
|
||||
await inputHandler.parseP('##########\x1b[3J');
|
||||
assert.equal(bufferService.buffer.x, 10);
|
||||
assert.deepEqual(getLines(bufferService), ['#'.repeat(10), '', '', '', '']);
|
||||
});
|
||||
});
|
||||
describe('following sequence keeps working', () => {
|
||||
// sequences to test (cursor related ones)
|
||||
const SEQ = [
|
||||
/* ICH */ '\x1b[10@',
|
||||
/* SL */ '\x1b[10 @',
|
||||
/* CUU */ '\x1b[10A',
|
||||
/* SR */ '\x1b[10 A',
|
||||
/* CUD */ '\x1b[10B',
|
||||
/* CUF */ '\x1b[10C',
|
||||
/* CUB */ '\x1b[10D',
|
||||
/* CNL */ '\x1b[10E',
|
||||
/* CPL */ '\x1b[10F',
|
||||
/* CHA */ '\x1b[10G',
|
||||
/* CUP */ '\x1b[10;10H',
|
||||
/* CHT */ '\x1b[10I',
|
||||
/* IL */ '\x1b[10L',
|
||||
/* DL */ '\x1b[10M',
|
||||
/* DCH */ '\x1b[10P',
|
||||
/* SU */ '\x1b[10S',
|
||||
/* SD */ '\x1b[10T',
|
||||
/* ECH */ '\x1b[10X',
|
||||
/* CBT */ '\x1b[10Z',
|
||||
/* HPA */ '\x1b[10`',
|
||||
/* HPR */ '\x1b[10a',
|
||||
/* REP */ '\x1b[10b',
|
||||
/* VPA */ '\x1b[10d',
|
||||
/* VPR */ '\x1b[10e',
|
||||
/* HVP */ '\x1b[10;10f',
|
||||
/* TBC */ '\x1b[0g',
|
||||
/* SCOSC */ '\x1b[s',
|
||||
/* DECIC */ '\x1b[10\'}',
|
||||
/* DECDC */ '\x1b[10\'~'
|
||||
];
|
||||
it('cursor never advances beyond cols', async () => {
|
||||
for (const seq of SEQ) {
|
||||
await inputHandler.parseP('##########\x1b[2J' + seq);
|
||||
assert.equal(bufferService.buffer.x <= bufferService.cols, true);
|
||||
inputHandler.reset();
|
||||
bufferService.reset();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -1247,7 +1247,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* @vt: #P[Protection attributes are not supported.] CSI DECSED "Selective Erase In Display" "CSI ? Ps J" "Currently the same as ED."
|
||||
*/
|
||||
public eraseInDisplay(params: IParams): boolean {
|
||||
this._restrictCursor();
|
||||
this._restrictCursor(this._bufferService.cols);
|
||||
let j;
|
||||
switch (params.params[0]) {
|
||||
case 0:
|
||||
@@ -1319,7 +1319,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
* @vt: #P[Protection attributes are not supported.] CSI DECSEL "Selective Erase In Line" "CSI ? Ps K" "Currently the same as EL."
|
||||
*/
|
||||
public eraseInLine(params: IParams): boolean {
|
||||
this._restrictCursor();
|
||||
this._restrictCursor(this._bufferService.cols);
|
||||
switch (params.params[0]) {
|
||||
case 0:
|
||||
this._eraseInBufferLine(this._bufferService.buffer.y, this._bufferService.buffer.x, this._bufferService.cols);
|
||||
|
||||
@@ -125,7 +125,7 @@ export class MockOptionsService implements IOptionsService {
|
||||
constructor(testOptions?: IPartialTerminalOptions) {
|
||||
if (testOptions) {
|
||||
for (const key of Object.keys(testOptions)) {
|
||||
this.options[key] = (<any>testOptions)[key];
|
||||
this.options[key] = (testOptions as any)[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ describe('BufferRange', () => {
|
||||
assert.throws(() => getRangeLength(createRange(1, 3, 1, 1), 0));
|
||||
});
|
||||
it('should get range multiple lines', () => {
|
||||
assert.equal(getRangeLength(createRange(1, 1, 4, 5), 5), 23);
|
||||
assert.equal(getRangeLength(createRange(1, 1, 4, 5), 5), 24);
|
||||
});
|
||||
it('should get range for end line right after start line', () => {
|
||||
assert.equal(getRangeLength(createRange(1, 1, 7, 2), 5), 11);
|
||||
assert.equal(getRangeLength(createRange(1, 1, 7, 2), 5), 12);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,12 +5,9 @@
|
||||
|
||||
import { IBufferRange } from 'xterm';
|
||||
|
||||
export function getRangeLength(range: IBufferRange, cols: number): number {
|
||||
if (range.start.y === range.end.y) {
|
||||
return range.end.x - range.start.x + 1;
|
||||
}
|
||||
export function getRangeLength(range: IBufferRange, bufferCols: number): number {
|
||||
if (range.start.y > range.end.y) {
|
||||
throw new Error(`Buffer range end (${range.end.x}, ${range.end.y}) cannot be before start (${range.start.x}, ${range.start.y})`);
|
||||
}
|
||||
return cols * (range.end.y - range.start.y - 1) + cols - range.start.x + range.end.x;
|
||||
return bufferCols * (range.end.y - range.start.y) + (range.end.x - range.start.x + 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user