Merge branch 'master' into master

This commit is contained in:
Daniel Imms
2018-12-17 11:46:33 -08:00
committed by GitHub
11 changed files with 358 additions and 406 deletions
+3 -4
View File
@@ -508,11 +508,10 @@ describe('Buffer', () => {
// the dangling last cell is wrongly added in the string
// --> fixable after resolving #1685
terminal.writeSync(input);
// TODO: reenable after fix
// const s = terminal.buffer.contents(true).toArray()[0];
// assert.equal(input, s);
const s = terminal.buffer.iterator(true).next().content;
assert.equal(input, s);
for (let i = 10; i < input.length; ++i) {
const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i + 1); // TODO: remove +1 after fix
const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i);
const j = (i - 0) << 1;
assert.deepEqual([(j / terminal.cols) | 0, j % terminal.cols], bufferIndex);
}
+8 -58
View File
@@ -17,9 +17,13 @@ export const CHAR_DATA_WIDTH_INDEX = 2;
export const CHAR_DATA_CODE_INDEX = 3;
export const MAX_BUFFER_SIZE = 4294967295; // 2^32 - 1
export const NULL_CELL_CHAR = ' ';
export const NULL_CELL_CHAR = '';
export const NULL_CELL_WIDTH = 1;
export const NULL_CELL_CODE = 32;
export const NULL_CELL_CODE = 0;
export const WHITESPACE_CELL_CHAR = ' ';
export const WHITESPACE_CELL_WIDTH = 1;
export const WHITESPACE_CELL_CODE = 32;
/**
* This class represents a terminal buffer (an internal state of the terminal), where the
@@ -272,64 +276,11 @@ export class Buffer implements IBuffer {
* @param endCol The column to end at.
*/
public translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol: number = 0, endCol: number = null): string {
// Get full line
let lineString = '';
const line = this.lines.get(lineIndex);
if (!line) {
return '';
}
// Initialize column and index values. Column values represent the actual
// cell column, indexes represent the index in the string. Indexes are
// needed here because some chars are 0 characters long (eg. after wide
// chars) and some chars are longer than 1 characters long (eg. emojis).
let startIndex = startCol;
// Only set endCol to the line length when it is null. 0 is a valid column.
if (endCol === null) {
endCol = line.length;
}
let endIndex = endCol;
for (let i = 0; i < line.length; i++) {
const char = line.get(i);
lineString += char[CHAR_DATA_CHAR_INDEX];
// Adjust start and end cols for wide characters if they affect their
// column indexes
if (char[CHAR_DATA_WIDTH_INDEX] === 0) {
if (startCol >= i) {
startIndex--;
}
if (endCol > i) {
endIndex--;
}
} else {
// Adjust the columns to take glyphs that are represented by multiple
// code points into account.
if (char[CHAR_DATA_CHAR_INDEX].length > 1) {
if (startCol > i) {
startIndex += char[CHAR_DATA_CHAR_INDEX].length - 1;
}
if (endCol > i) {
endIndex += char[CHAR_DATA_CHAR_INDEX].length - 1;
}
}
}
}
// Calculate the final end col by trimming whitespace on the right of the
// line if needed.
if (trimRight) {
const rightWhitespaceIndex = lineString.search(/\s+$/);
if (rightWhitespaceIndex !== -1) {
endIndex = Math.min(endIndex, rightWhitespaceIndex);
}
// Return the empty string if only trimmed whitespace is selected
if (endIndex <= startIndex) {
return '';
}
}
return lineString.substring(startIndex, endIndex);
return line.translateToString(trimRight, startCol, endCol);
}
public getWrappedRangeForLine(y: number): { first: number, last: number } {
@@ -488,8 +439,7 @@ export class BufferStringIterator implements IBufferStringIterator {
range.last = Math.min(range.last, this._buffer.lines.length);
let result = '';
for (let i = range.first; i <= range.last; ++i) {
// TODO: always apply trimRight after fixing #1685
result += this._buffer.translateBufferLineToString(i, (this._trimRight) ? i === range.last : false);
result += this._buffer.translateBufferLineToString(i, this._trimRight);
}
this._current = range.last + 1;
return {range: range, content: result};
+127 -1
View File
@@ -5,7 +5,7 @@
import * as chai from 'chai';
import { BufferLine } from './BufferLine';
import { CharData, IBufferLine } from './Types';
import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Buffer';
import { NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR } from './Buffer';
class TestBufferLine extends BufferLine {
@@ -200,4 +200,130 @@ describe('BufferLine', function(): void {
chai.expect(line.toArray()).eql(Array(7).fill([1, 'a', 0, 'a'.charCodeAt(0)]));
});
});
describe('getTrimLength', function(): void {
it('empty line', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
chai.expect(line.getTrimmedLength()).equal(0);
});
it('ASCII', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, 'a', 1, 'a'.charCodeAt(0)]);
chai.expect(line.getTrimmedLength()).equal(3);
});
it('surrogate', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, '𝄞', 1, '𝄞'.charCodeAt(0)]);
chai.expect(line.getTrimmedLength()).equal(3);
});
it('combining', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
chai.expect(line.getTrimmedLength()).equal(3);
});
it('fullwidth', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, '', 2, ''.charCodeAt(0)]);
line.set(3, [0, '', 0, undefined]);
chai.expect(line.getTrimmedLength()).equal(4); // also counts null cell after fullwidth
});
});
describe('translateToString with and w\'o trimming', function(): void {
it('empty line', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
chai.expect(line.translateToString(false)).equal(' ');
chai.expect(line.translateToString(true)).equal('');
});
it('ASCII', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(4, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(5, [1, 'a', 1, 'a'.charCodeAt(0)]);
chai.expect(line.translateToString(false)).equal('a a aa ');
chai.expect(line.translateToString(true)).equal('a a aa');
chai.expect(line.translateToString(false, 0, 5)).equal('a a a');
chai.expect(line.translateToString(false, 0, 4)).equal('a a ');
chai.expect(line.translateToString(false, 0, 3)).equal('a a');
chai.expect(line.translateToString(true, 0, 5)).equal('a a a');
chai.expect(line.translateToString(true, 0, 4)).equal('a a ');
chai.expect(line.translateToString(true, 0, 3)).equal('a a');
});
it('surrogate', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, '𝄞', 1, '𝄞'.charCodeAt(0)]);
line.set(4, [1, '𝄞', 1, '𝄞'.charCodeAt(0)]);
line.set(5, [1, '𝄞', 1, '𝄞'.charCodeAt(0)]);
chai.expect(line.translateToString(false)).equal('a 𝄞 𝄞𝄞 ');
chai.expect(line.translateToString(true)).equal('a 𝄞 𝄞𝄞');
chai.expect(line.translateToString(false, 0, 5)).equal('a 𝄞 𝄞');
chai.expect(line.translateToString(false, 0, 4)).equal('a 𝄞 ');
chai.expect(line.translateToString(false, 0, 3)).equal('a 𝄞');
chai.expect(line.translateToString(true, 0, 5)).equal('a 𝄞 𝄞');
chai.expect(line.translateToString(true, 0, 4)).equal('a 𝄞 ');
chai.expect(line.translateToString(true, 0, 3)).equal('a 𝄞');
});
it('combining', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
line.set(4, [1, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
line.set(5, [1, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
chai.expect(line.translateToString(false)).equal('a e\u0301 e\u0301e\u0301 ');
chai.expect(line.translateToString(true)).equal('a e\u0301 e\u0301e\u0301');
chai.expect(line.translateToString(false, 0, 5)).equal('a e\u0301 e\u0301');
chai.expect(line.translateToString(false, 0, 4)).equal('a e\u0301 ');
chai.expect(line.translateToString(false, 0, 3)).equal('a e\u0301');
chai.expect(line.translateToString(true, 0, 5)).equal('a e\u0301 e\u0301');
chai.expect(line.translateToString(true, 0, 4)).equal('a e\u0301 ');
chai.expect(line.translateToString(true, 0, 3)).equal('a e\u0301');
});
it('fullwidth', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, '', 2, ''.charCodeAt(0)]);
line.set(3, [0, '', 0, undefined]);
line.set(5, [1, '', 2, ''.charCodeAt(0)]);
line.set(6, [0, '', 0, undefined]);
line.set(7, [1, '', 2, ''.charCodeAt(0)]);
line.set(8, [0, '', 0, undefined]);
chai.expect(line.translateToString(false)).equal('a 11 ');
chai.expect(line.translateToString(true)).equal('a 11');
chai.expect(line.translateToString(false, 0, 7)).equal('a ');
chai.expect(line.translateToString(false, 0, 6)).equal('a ');
chai.expect(line.translateToString(false, 0, 5)).equal('a ');
chai.expect(line.translateToString(false, 0, 4)).equal('a ');
chai.expect(line.translateToString(false, 0, 3)).equal('a ');
chai.expect(line.translateToString(false, 0, 2)).equal('a ');
chai.expect(line.translateToString(true, 0, 7)).equal('a ');
chai.expect(line.translateToString(true, 0, 6)).equal('a ');
chai.expect(line.translateToString(true, 0, 5)).equal('a ');
chai.expect(line.translateToString(true, 0, 4)).equal('a ');
chai.expect(line.translateToString(true, 0, 3)).equal('a ');
chai.expect(line.translateToString(true, 0, 2)).equal('a ');
});
it('space at end', function(): void {
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE], false);
line.set(0, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(2, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(4, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(5, [1, 'a', 1, 'a'.charCodeAt(0)]);
line.set(6, [1, ' ', 1, ' '.charCodeAt(0)]);
chai.expect(line.translateToString(false)).equal('a a aa ');
chai.expect(line.translateToString(true)).equal('a a aa ');
});
it('should always return some sane value', function(): void {
// sanity check - broken line with invalid out of bound null width cells
// this can atm happen with deleting/inserting chars in inputhandler by "breaking"
// fullwidth pairs --> needs to be fixed after settling BufferLine impl
const line = new TestBufferLine(10, [DEFAULT_ATTR, NULL_CELL_CHAR, 0, NULL_CELL_CODE], false);
chai.expect(line.translateToString(false)).equal(' ');
chai.expect(line.translateToString(true)).equal('');
});
});
});
+53 -4
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { CharData, IBufferLine } from './Types';
import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR } from './Buffer';
import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, WHITESPACE_CELL_CHAR } from './Buffer';
/**
* Class representing a terminal line.
@@ -107,6 +107,29 @@ export class BufferLineJSArray implements IBufferLine {
newLine.copyFrom(this);
return newLine;
}
public getTrimmedLength(): number {
for (let i = this.length - 1; i >= 0; --i) {
const ch = this.get(i);
if (ch[CHAR_DATA_CHAR_INDEX] !== '') {
return i + ch[CHAR_DATA_WIDTH_INDEX];
}
}
return 0;
}
public translateToString(trimRight: boolean = false, startCol: number = 0, endCol: number = null): string {
let length = endCol || this.length;
if (trimRight) {
length = Math.min(length, this.getTrimmedLength());
}
let result = '';
while (startCol < length) {
result += this.get(startCol)[CHAR_DATA_CHAR_INDEX] || WHITESPACE_CELL_CHAR;
startCol += this.get(startCol)[CHAR_DATA_WIDTH_INDEX] || 1;
}
return result;
}
}
/** typed array slots taken by one cell */
@@ -119,6 +142,9 @@ const enum Cell {
WIDTH = 2
}
/** single vs. combined char distinction */
const IS_COMBINED_BIT_MASK = 0x80000000;
/**
* Typed array based bufferline implementation.
*/
@@ -144,11 +170,11 @@ export class BufferLine implements IBufferLine {
const stringData = this._data[index * CELL_SIZE + Cell.STRING];
return [
this._data[index * CELL_SIZE + Cell.FLAGS],
(stringData & 0x80000000)
(stringData & IS_COMBINED_BIT_MASK)
? this._combined[index]
: (stringData) ? String.fromCharCode(stringData) : '',
this._data[index * CELL_SIZE + Cell.WIDTH],
(stringData & 0x80000000)
(stringData & IS_COMBINED_BIT_MASK)
? this._combined[index].charCodeAt(this._combined[index].length - 1)
: stringData
];
@@ -158,7 +184,7 @@ export class BufferLine implements IBufferLine {
this._data[index * CELL_SIZE + Cell.FLAGS] = value[0];
if (value[1].length > 1) {
this._combined[index] = value[1];
this._data[index * CELL_SIZE + Cell.STRING] = index | 0x80000000;
this._data[index * CELL_SIZE + Cell.STRING] = index | IS_COMBINED_BIT_MASK;
} else {
this._data[index * CELL_SIZE + Cell.STRING] = value[1].charCodeAt(0);
}
@@ -269,4 +295,27 @@ export class BufferLine implements IBufferLine {
newLine.isWrapped = this.isWrapped;
return newLine;
}
public getTrimmedLength(): number {
for (let i = this.length - 1; i >= 0; --i) {
if (this._data[i * CELL_SIZE + Cell.STRING] !== 0) { // 0 ==> ''.charCodeAt(0) ==> NaN ==> 0
return i + this._data[i * CELL_SIZE + Cell.WIDTH];
}
}
return 0;
}
public translateToString(trimRight: boolean = false, startCol: number = 0, endCol: number = null): string {
let length = endCol || this.length;
if (trimRight) {
length = Math.min(length, this.getTrimmedLength());
}
let result = '';
while (startCol < length) {
const stringData = this._data[startCol * CELL_SIZE + Cell.STRING];
result += (stringData & IS_COMBINED_BIT_MASK) ? this._combined[startCol] : (stringData) ? String.fromCharCode(stringData) : WHITESPACE_CELL_CHAR;
startCol += this._data[startCol * CELL_SIZE + Cell.WIDTH] || 1;
}
return result;
}
}
+137 -309
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -13,7 +13,7 @@ import * as path from 'path';
import * as pty from 'node-pty';
import { assert } from 'chai';
import { Terminal } from './Terminal';
import { CHAR_DATA_CHAR_INDEX } from './Buffer';
import { CHAR_DATA_CHAR_INDEX, WHITESPACE_CELL_CHAR } from './Buffer';
import { IViewport } from './Types';
class TestTerminal extends Terminal {
@@ -67,7 +67,7 @@ function terminalToString(term: Terminal): string {
for (let line = term.buffer.ybase; line < term.buffer.ybase + term.rows; line++) {
lineText = '';
for (let cell = 0; cell < term.cols; ++cell) {
lineText += term.buffer.lines.get(line).get(cell)[CHAR_DATA_CHAR_INDEX];
lineText += term.buffer.lines.get(line).get(cell)[CHAR_DATA_CHAR_INDEX] || WHITESPACE_CELL_CHAR;
}
// rtrim empty cells as xterm does
lineText = lineText.replace(/\s+$/, '');
+21 -21
View File
@@ -462,7 +462,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.length, INIT_ROWS + 1);
assert.equal(term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX], 'a');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).get(0)[CHAR_DATA_CHAR_INDEX], 'b');
assert.equal(term.buffer.lines.get(INIT_ROWS).get(0)[CHAR_DATA_CHAR_INDEX], ' ');
assert.equal(term.buffer.lines.get(INIT_ROWS).get(0)[CHAR_DATA_CHAR_INDEX], '');
});
it('should properly scroll inside a scroll region (scrollTop set)', () => {
@@ -491,7 +491,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX], 'b');
assert.equal(term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX], 'c');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], 'd');
assert.equal(term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX], ' ', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX], '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(5).get(0)[CHAR_DATA_CHAR_INDEX], 'e');
});
@@ -509,7 +509,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX], 'a');
assert.equal(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX], 'c', '\'b\' should be removed from the buffer');
assert.equal(term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX], 'd');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], ' ', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX], 'e');
});
});
@@ -530,9 +530,9 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.length, INIT_ROWS);
// 'a' gets pushed out of buffer
assert.equal(term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX], 'b');
assert.equal(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX], ' ');
assert.equal(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX], '');
assert.equal(term.buffer.lines.get(INIT_ROWS - 2).get(0)[CHAR_DATA_CHAR_INDEX], 'c');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).get(0)[CHAR_DATA_CHAR_INDEX], ' ');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).get(0)[CHAR_DATA_CHAR_INDEX], '');
});
it('should properly scroll inside a scroll region (scrollTop set)', () => {
@@ -560,7 +560,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX], 'b');
assert.equal(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX], 'c');
assert.equal(term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX], 'd');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], ' ', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX], 'e');
});
@@ -578,7 +578,7 @@ describe('term.js addons', () => {
assert.equal(term.buffer.lines.get(0).get(0)[CHAR_DATA_CHAR_INDEX], 'a');
assert.equal(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX], 'c', '\'b\' should be removed from the buffer');
assert.equal(term.buffer.lines.get(2).get(0)[CHAR_DATA_CHAR_INDEX], 'd');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], ' ', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(3).get(0)[CHAR_DATA_CHAR_INDEX], '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).get(0)[CHAR_DATA_CHAR_INDEX], 'e');
});
});
@@ -776,7 +776,7 @@ describe('term.js addons', () => {
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql(high + String.fromCharCode(i));
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(2);
expect(tchar[CHAR_DATA_WIDTH_INDEX]).eql(1);
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX]).eql('');
term.reset();
}
});
@@ -787,7 +787,7 @@ describe('term.js addons', () => {
term.write(high + String.fromCharCode(i));
expect(term.buffer.lines.get(0).get(term.buffer.x - 1)[CHAR_DATA_CHAR_INDEX]).eql(high + String.fromCharCode(i));
expect(term.buffer.lines.get(0).get(term.buffer.x - 1)[CHAR_DATA_CHAR_INDEX].length).eql(2);
expect(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX]).eql('');
term.reset();
}
});
@@ -800,7 +800,7 @@ describe('term.js addons', () => {
expect(term.buffer.lines.get(0).get(term.cols - 1)[CHAR_DATA_CHAR_INDEX]).eql('a');
expect(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX]).eql(high + String.fromCharCode(i));
expect(term.buffer.lines.get(1).get(0)[CHAR_DATA_CHAR_INDEX].length).eql(2);
expect(term.buffer.lines.get(1).get(1)[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(term.buffer.lines.get(1).get(1)[CHAR_DATA_CHAR_INDEX]).eql('');
term.reset();
}
});
@@ -813,7 +813,7 @@ describe('term.js addons', () => {
// auto wraparound mode should cut off the rest of the line
expect(term.buffer.lines.get(0).get(term.cols - 1)[CHAR_DATA_CHAR_INDEX]).eql('a');
expect(term.buffer.lines.get(0).get(term.cols - 1)[CHAR_DATA_CHAR_INDEX].length).eql(1);
expect(term.buffer.lines.get(1).get(1)[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(term.buffer.lines.get(1).get(1)[CHAR_DATA_CHAR_INDEX]).eql('');
term.reset();
}
});
@@ -826,7 +826,7 @@ describe('term.js addons', () => {
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql(high + String.fromCharCode(i));
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(2);
expect(tchar[CHAR_DATA_WIDTH_INDEX]).eql(1);
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX]).eql('');
term.reset();
}
});
@@ -845,8 +845,8 @@ describe('term.js addons', () => {
expect(term.buffer.lines.get(0).get(term.cols - 1)[CHAR_DATA_CHAR_INDEX]).eql('e\u0301');
expect(term.buffer.lines.get(0).get(term.cols - 1)[CHAR_DATA_CHAR_INDEX].length).eql(2);
expect(term.buffer.lines.get(0).get(term.cols - 1)[CHAR_DATA_WIDTH_INDEX]).eql(1);
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX].length).eql(1);
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX]).eql('');
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_CHAR_INDEX].length).eql(0);
expect(term.buffer.lines.get(0).get(1)[CHAR_DATA_WIDTH_INDEX]).eql(1);
});
it('multiple combined é', () => {
@@ -928,8 +928,8 @@ describe('term.js addons', () => {
}
}
let tchar = term.buffer.lines.get(0).get(term.cols - 1);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(1);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql('');
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(0);
expect(tchar[CHAR_DATA_WIDTH_INDEX]).eql(1);
tchar = term.buffer.lines.get(1).get(0);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql('¥');
@@ -953,8 +953,8 @@ describe('term.js addons', () => {
}
}
let tchar = term.buffer.lines.get(0).get(term.cols - 1);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(1);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql('');
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(0);
expect(tchar[CHAR_DATA_WIDTH_INDEX]).eql(1);
tchar = term.buffer.lines.get(1).get(0);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql('¥\u0301');
@@ -998,8 +998,8 @@ describe('term.js addons', () => {
}
}
let tchar = term.buffer.lines.get(0).get(term.cols - 1);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql(' ');
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(1);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql('');
expect(tchar[CHAR_DATA_CHAR_INDEX].length).eql(0);
expect(tchar[CHAR_DATA_WIDTH_INDEX]).eql(1);
tchar = term.buffer.lines.get(1).get(0);
expect(tchar[CHAR_DATA_CHAR_INDEX]).eql('\ud843\ude6d\u0301');
@@ -1063,7 +1063,7 @@ describe('term.js addons', () => {
expect(term.buffer.lines.get(0).length).eql(term.cols);
expect(term.buffer.lines.get(0).get(10)[CHAR_DATA_CHAR_INDEX]).eql('a');
expect(term.buffer.lines.get(0).get(11)[CHAR_DATA_CHAR_INDEX]).eql('¥');
expect(term.buffer.lines.get(0).get(79)[CHAR_DATA_CHAR_INDEX]).eql(' '); // fullwidth char got replaced
expect(term.buffer.lines.get(0).get(79)[CHAR_DATA_CHAR_INDEX]).eql(''); // fullwidth char got replaced
term.write('b');
expect(term.buffer.lines.get(0).length).eql(term.cols);
expect(term.buffer.lines.get(0).get(11)[CHAR_DATA_CHAR_INDEX]).eql('b');
+2
View File
@@ -524,6 +524,8 @@ export interface IBufferLine {
fill(fillCharData: CharData): void;
copyFrom(line: IBufferLine): void;
clone(): IBufferLine;
getTrimmedLength(): number;
translateToString(trimRight?: boolean, startCol?: number, endCol?: number): string;
}
export interface IBufferLineConstructor {
-2
View File
@@ -118,8 +118,6 @@ describe('search addon', () => {
it('should not select empty lines', () => {
search.apply(<any>MockTerminal);
const term = new MockTerminal({cols: 20, rows: 3});
term.core.write(' ');
term.pushWriteData();
const line = term.searchHelper.findInLine('^.*$', 0, { regex: true });
expect(line).eql(undefined);
});
+3 -3
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { CHAR_DATA_ATTR_INDEX, CHAR_DATA_CODE_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, NULL_CELL_CODE } from '../Buffer';
import { CHAR_DATA_ATTR_INDEX, CHAR_DATA_CODE_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../Buffer';
import { FLAGS, IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { CharData, ITerminal } from '../Types';
import { INVERTED_DEFAULT_COLOR, DEFAULT_COLOR } from './atlas/Types';
@@ -73,11 +73,11 @@ export class TextRenderLayer extends BaseRenderLayer {
const joinedRanges = joinerRegistry ? joinerRegistry.getJoinedCharacters(row) : [];
for (let x = 0; x < terminal.cols; x++) {
const charData = line.get(x);
let code: number = <number>charData[CHAR_DATA_CODE_INDEX];
let code: number = <number>charData[CHAR_DATA_CODE_INDEX] || WHITESPACE_CELL_CODE;
// Can either represent character(s) for a single cell or multiple cells
// if indicated by a character joiner.
let chars: string = charData[CHAR_DATA_CHAR_INDEX];
let chars: string = charData[CHAR_DATA_CHAR_INDEX] || WHITESPACE_CELL_CHAR;
const attr: number = charData[CHAR_DATA_ATTR_INDEX];
let width: number = charData[CHAR_DATA_WIDTH_INDEX];
+2 -2
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE } from '../../Buffer';
import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../Buffer';
import { FLAGS } from '../Types';
import { IBufferLine } from '../../Types';
import { DEFAULT_COLOR, INVERTED_DEFAULT_COLOR } from '../atlas/Types';
@@ -41,7 +41,7 @@ export class DomRendererRowFactory {
for (let x = 0; x < lineLength; x++) {
const charData = lineData.get(x);
const char = charData[CHAR_DATA_CHAR_INDEX];
const char = charData[CHAR_DATA_CHAR_INDEX] || WHITESPACE_CELL_CHAR;
const attr = charData[CHAR_DATA_ATTR_INDEX];
const width = charData[CHAR_DATA_WIDTH_INDEX];