Merge branch 'utf32_buffer' into utf8_input

This commit is contained in:
Jörg Breitbart
2019-02-01 01:11:58 +01:00
14 changed files with 217 additions and 217 deletions
+9 -9
View File
@@ -37,13 +37,13 @@ describe('Buffer', () => {
describe('fillViewportRows', () => {
it('should fill the buffer with blank lines based on the size of the viewport', () => {
const blankLineChar = buffer.getBlankLine(DEFAULT_ATTR).loadCell(0, new CellData()).asCharData;
const blankLineChar = buffer.getBlankLine(DEFAULT_ATTR).loadCell(0, new CellData()).getAsCharData;
buffer.fillViewportRows();
assert.equal(buffer.lines.length, INIT_ROWS);
for (let y = 0; y < INIT_ROWS; y++) {
assert.equal(buffer.lines.get(y).length, INIT_COLS);
for (let x = 0; x < INIT_COLS; x++) {
assert.deepEqual(buffer.lines.get(y).loadCell(x, new CellData()).asCharData, blankLineChar);
assert.deepEqual(buffer.lines.get(y).loadCell(x, new CellData()).getAsCharData, blankLineChar);
}
}
});
@@ -155,15 +155,15 @@ describe('Buffer', () => {
assert.equal(buffer.lines.maxLength, INIT_ROWS);
buffer.y = INIT_ROWS - 1;
buffer.fillViewportRows();
let chData = buffer.lines.get(5).loadCell(0, new CellData()).asCharData;
let chData = buffer.lines.get(5).loadCell(0, new CellData()).getAsCharData();
chData[1] = 'a';
buffer.lines.get(5).setCell(0, CellData.fromCharData(chData));
chData = buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).asCharData;
chData = buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).getAsCharData();
chData[1] = 'b';
buffer.lines.get(INIT_ROWS - 1).setCell(0, CellData.fromCharData(chData));
buffer.resize(INIT_COLS, INIT_ROWS - 5);
assert.equal(buffer.lines.get(0).loadCell(0, new CellData()).asCharData[1], 'a');
assert.equal(buffer.lines.get(INIT_ROWS - 1 - 5).loadCell(0, new CellData()).asCharData[1], 'b');
assert.equal(buffer.lines.get(0).loadCell(0, new CellData()).getAsCharData()[1], 'a');
assert.equal(buffer.lines.get(INIT_ROWS - 1 - 5).loadCell(0, new CellData()).getAsCharData()[1], 'b');
});
});
});
@@ -1264,7 +1264,7 @@ describe('Buffer', () => {
assert.equal(input, s);
const stringIndex = s.match(/😃/).index;
const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, stringIndex);
assert(terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).chars, '😃');
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)', () => {
@@ -1291,7 +1291,7 @@ describe('Buffer', () => {
assert.equal(input, s);
for (let i = 0; i < input.length; ++i) {
const bufferIndex = terminal.buffer.stringIndexToBufferIndex(0, i, true);
assert.equal(input[i], terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).chars);
assert.equal(input[i], terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).getChars());
}
});
@@ -1309,7 +1309,7 @@ describe('Buffer', () => {
: (i % 3 === 1)
? input.substr(i, 2)
: input.substr(i - 1, 2),
terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).chars);
terminal.buffer.lines.get(bufferIndex[0]).loadCell(bufferIndex[1], new CellData()).getChars());
}
});
+20 -20
View File
@@ -16,7 +16,7 @@ class TestBufferLine extends BufferLine {
public toArray(): CharData[] {
const result = [];
for (let i = 0; i < this.length; ++i) {
result.push(this.loadCell(i, new CellData()).asCharData);
result.push(this.loadCell(i, new CellData()).getAsCharData());
}
return result;
}
@@ -27,24 +27,24 @@ describe('CellData', () => {
const cell = new CellData();
// ASCII
cell.setFromCharData([123, 'a', 1, 'a'.charCodeAt(0)]);
chai.assert.deepEqual(cell.asCharData, [123, 'a', 1, 'a'.charCodeAt(0)]);
chai.assert.equal(cell.isCombined, 0);
chai.assert.deepEqual(cell.getAsCharData(), [123, 'a', 1, 'a'.charCodeAt(0)]);
chai.assert.equal(cell.isCombined(), 0);
// combining
cell.setFromCharData([123, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
chai.assert.deepEqual(cell.asCharData, [123, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
chai.assert.equal(cell.isCombined, Content.IS_COMBINED);
chai.assert.deepEqual(cell.getAsCharData(), [123, 'e\u0301', 1, '\u0301'.charCodeAt(0)]);
chai.assert.equal(cell.isCombined(), Content.IS_COMBINED);
// surrogate
cell.setFromCharData([123, '𝄞', 1, 0x1D11E]);
chai.assert.deepEqual(cell.asCharData, [123, '𝄞', 1, 0x1D11E]);
chai.assert.equal(cell.isCombined, 0);
chai.assert.deepEqual(cell.getAsCharData(), [123, '𝄞', 1, 0x1D11E]);
chai.assert.equal(cell.isCombined(), 0);
// surrogate + combining
cell.setFromCharData([123, '𓂀\u0301', 1, '𓂀\u0301'.charCodeAt(2)]);
chai.assert.deepEqual(cell.asCharData, [123, '𓂀\u0301', 1, '𓂀\u0301'.charCodeAt(2)]);
chai.assert.equal(cell.isCombined, Content.IS_COMBINED);
chai.assert.deepEqual(cell.getAsCharData(), [123, '𓂀\u0301', 1, '𓂀\u0301'.charCodeAt(2)]);
chai.assert.equal(cell.isCombined(), Content.IS_COMBINED);
// wide char
cell.setFromCharData([123, '', 2, ''.charCodeAt(0)]);
chai.assert.deepEqual(cell.asCharData, [123, '', 2, ''.charCodeAt(0)]);
chai.assert.equal(cell.isCombined, 0);
chai.assert.deepEqual(cell.getAsCharData(), [123, '', 2, ''.charCodeAt(0)]);
chai.assert.equal(cell.isCombined(), 0);
});
});
@@ -55,15 +55,15 @@ describe('BufferLine', function(): void {
chai.expect(line.isWrapped).equals(false);
line = new TestBufferLine(10);
chai.expect(line.length).equals(10);
chai.expect(line.loadCell(0, new CellData()).asCharData).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
chai.expect(line.isWrapped).equals(false);
line = new TestBufferLine(10, null, true);
chai.expect(line.length).equals(10);
chai.expect(line.loadCell(0, new CellData()).asCharData).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([0, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]);
chai.expect(line.isWrapped).equals(true);
line = new TestBufferLine(10, CellData.fromCharData([123, 'a', 456, 'a'.charCodeAt(0)]), true);
chai.expect(line.length).equals(10);
chai.expect(line.loadCell(0, new CellData()).asCharData).eql([123, 'a', 456, 'a'.charCodeAt(0)]);
chai.expect(line.loadCell(0, new CellData()).getAsCharData()).eql([123, 'a', 456, 'a'.charCodeAt(0)]);
chai.expect(line.isWrapped).equals(true);
});
it('insertCells', function(): void {
@@ -335,9 +335,9 @@ describe('BufferLine', function(): void {
const cell = line.loadCell(0, new CellData());
// chars contains single combining char
// width is set to 1
chai.assert.deepEqual(cell.asCharData, [DEFAULT_ATTR, '\u0301', 1, 0x0301]);
chai.assert.deepEqual(cell.getAsCharData(), [DEFAULT_ATTR, '\u0301', 1, 0x0301]);
// do not account a single combining char as combined
chai.assert.equal(cell.isCombined, 0);
chai.assert.equal(cell.isCombined(), 0);
});
it('should add char to combining string in cell', () => {
const line = new TestBufferLine(3, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]), false);
@@ -348,9 +348,9 @@ describe('BufferLine', function(): void {
line.loadCell(0, cell);
// chars contains 3 chars
// width is set to 1
chai.assert.deepEqual(cell.asCharData, [123, 'e\u0301\u0301', 1, 0x0301]);
chai.assert.deepEqual(cell.getAsCharData(), [123, 'e\u0301\u0301', 1, 0x0301]);
// do not account a single combining char as combined
chai.assert.equal(cell.isCombined, Content.IS_COMBINED);
chai.assert.equal(cell.isCombined(), Content.IS_COMBINED);
});
it('should create combining string on taken cell', () => {
const line = new TestBufferLine(3, CellData.fromCharData([DEFAULT_ATTR, NULL_CELL_CHAR, NULL_CELL_WIDTH, NULL_CELL_CODE]), false);
@@ -361,9 +361,9 @@ describe('BufferLine', function(): void {
line.loadCell(0, cell);
// chars contains 2 chars
// width is set to 1
chai.assert.deepEqual(cell.asCharData, [123, 'e\u0301', 1, 0x0301]);
chai.assert.deepEqual(cell.getAsCharData(), [123, 'e\u0301', 1, 0x0301]);
// do not account a single combining char as combined
chai.assert.equal(cell.isCombined, Content.IS_COMBINED);
chai.assert.equal(cell.isCombined(), Content.IS_COMBINED);
});
});
});
+7 -7
View File
@@ -95,17 +95,17 @@ export class CellData implements ICellData {
public combinedData: string = '';
/** Whether cell contains a combined string. */
public get isCombined(): number {
public isCombined(): number {
return this.content & Content.IS_COMBINED;
}
/** Width of the cell. */
public get width(): number {
public getWidth(): number {
return this.content >> Content.WIDTH_SHIFT;
}
/** JS string of the content. */
public get chars(): string {
public getChars(): string {
if (this.content & Content.IS_COMBINED) {
return this.combinedData;
}
@@ -121,8 +121,8 @@ export class CellData implements ICellData {
* if content is a combined string it returns the codepoint
* of the last char in string to be in line with code in CharData.
* */
public get code(): number {
return (this.isCombined)
public getCode(): number {
return (this.isCombined())
? this.combinedData.charCodeAt(this.combinedData.length - 1)
: this.content & Content.CODEPOINT_MASK;
}
@@ -160,8 +160,8 @@ export class CellData implements ICellData {
}
/** Get data as CharData. */
public get asCharData(): CharData {
return [this.fg, this.chars, this.width, this.code];
public getAsCharData(): CharData {
return [this.fg, this.getChars(), this.getWidth(), this.getCode()];
}
}
+1 -1
View File
@@ -23,7 +23,7 @@ describe('getStringCellWidth', function(): void {
for (let i = start; i < end; ++i) {
const line = buffer.lines.get(i);
for (let j = 0; j < line.length; ++j) { // TODO: change to trimBorder with multiline
const ch = line.loadCell(j, new CellData()).asCharData;
const ch = line.loadCell(j, new CellData()).getAsCharData();
result += ch[CHAR_DATA_WIDTH_INDEX];
// return on sentinel
if (ch[CHAR_DATA_CHAR_INDEX] === sentinel) {
+2 -2
View File
@@ -378,7 +378,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// since they always follow a cell consuming char
// therefore we can test for buffer.x to avoid overflow left
if (!chWidth && buffer.x) {
if (!bufferRow.loadCell(buffer.x - 1, this._cell).width) {
if (!bufferRow.loadCell(buffer.x - 1, this._cell).getWidth()) {
// found empty cell after fullwidth, need to go 2 cells back
// it is save to step 2 cells back here
// since an empty cell is only set by fullwidth chars
@@ -427,7 +427,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test last cell - since the last cell has only room for
// a halfwidth char any fullwidth shifted there is lost
// and will be set to empty cell
if (bufferRow.loadCell(cols - 1, this._cell).width === 2) {
if (bufferRow.loadCell(cols - 1, this._cell).getWidth() === 2) {
bufferRow.setCellFromCodePoint(cols - 1, NULL_CELL_CODE, NULL_CELL_WIDTH, curAttr, 0);
}
}
+8 -8
View File
@@ -669,8 +669,8 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
private _convertViewportColToCharacterIndex(bufferLine: IBufferLine, coords: [number, number]): number {
let charIndex = coords[0];
for (let i = 0; coords[0] >= i; i++) {
const length = bufferLine.loadCell(i, this._cell).chars.length;
if (this._cell.width === 0) {
const length = bufferLine.loadCell(i, this._cell).getChars().length;
if (this._cell.getWidth() === 0) {
// Wide characters aren't included in the line string so decrement the
// index so the index is back on the wide character.
charIndex--;
@@ -757,8 +757,8 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
// Expand the string in both directions until a space is hit
while (startCol > 0 && startIndex > 0 && !this._isCharWordSeparator(bufferLine.loadCell(startCol - 1, this._cell))) {
bufferLine.loadCell(startCol - 1, this._cell);
const length = this._cell.chars.length;
if (this._cell.width === 0) {
const length = this._cell.getChars().length;
if (this._cell.getWidth() === 0) {
// If the next character is a wide char, record it and skip the column
leftWideCharCount++;
startCol--;
@@ -773,8 +773,8 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
}
while (endCol < bufferLine.length && endIndex + 1 < line.length && !this._isCharWordSeparator(bufferLine.loadCell(endCol + 1, this._cell))) {
bufferLine.loadCell(endCol + 1, this._cell);
const length = this._cell.chars.length;
if (this._cell.width === 2) {
const length = this._cell.getChars().length;
if (this._cell.getWidth() === 2) {
// If the next character is a wide char, record it and skip the column
rightWideCharCount++;
endCol++;
@@ -899,10 +899,10 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
private _isCharWordSeparator(cell: CellData): boolean {
// Zero width characters are never separators as they are always to the
// right of wide characters
if (cell.width === 0) {
if (cell.getWidth() === 0) {
return false;
}
return WORD_SEPARATORS.indexOf(cell.chars) >= 0;
return WORD_SEPARATORS.indexOf(cell.getChars()) >= 0;
}
/**
+1 -1
View File
@@ -68,7 +68,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).loadCell(cell, new CellData()).chars || WHITESPACE_CELL_CHAR;
lineText += term.buffer.lines.get(line).loadCell(cell, new CellData()).getChars() || WHITESPACE_CELL_CHAR;
}
// rtrim empty cells as xterm does
lineText = lineText.replace(/\s+$/, '');
+149 -149
View File
@@ -461,9 +461,9 @@ describe('term.js addons', () => {
term.buffer.y = INIT_ROWS - 1; // Move cursor to last line
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS + 1);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'a');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).chars, 'b');
assert.equal(term.buffer.lines.get(INIT_ROWS).loadCell(0, new CellData()).chars, '');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).getChars(), 'b');
assert.equal(term.buffer.lines.get(INIT_ROWS).loadCell(0, new CellData()).getChars(), '');
});
it('should properly scroll inside a scroll region (scrollTop set)', () => {
@@ -474,8 +474,8 @@ describe('term.js addons', () => {
term.buffer.scrollTop = 1;
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, 'c');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c');
});
it('should properly scroll inside a scroll region (scrollBottom set)', () => {
@@ -488,12 +488,12 @@ describe('term.js addons', () => {
term.buffer.scrollBottom = 3;
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS + 1);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'a', '\'a\' should be pushed to the scrollback');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, 'b');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).chars, 'c');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).chars, 'd');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).chars, '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(5).loadCell(0, new CellData()).chars, 'e');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a', '\'a\' should be pushed to the scrollback');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'b');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'c');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), 'd');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(5).loadCell(0, new CellData()).getChars(), 'e');
});
it('should properly scroll inside a scroll region (scrollTop and scrollBottom set)', () => {
@@ -507,11 +507,11 @@ describe('term.js addons', () => {
term.buffer.scrollBottom = 3;
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, 'c', '\'b\' should be removed from the buffer');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).chars, 'd');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).chars, '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).chars, 'e');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'd');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), 'e');
});
});
@@ -530,10 +530,10 @@ describe('term.js addons', () => {
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS);
// 'a' gets pushed out of buffer
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'b');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, '');
assert.equal(term.buffer.lines.get(INIT_ROWS - 2).loadCell(0, new CellData()).chars, 'c');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).chars, '');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'b');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), '');
assert.equal(term.buffer.lines.get(INIT_ROWS - 2).loadCell(0, new CellData()).getChars(), 'c');
assert.equal(term.buffer.lines.get(INIT_ROWS - 1).loadCell(0, new CellData()).getChars(), '');
});
it('should properly scroll inside a scroll region (scrollTop set)', () => {
@@ -544,8 +544,8 @@ describe('term.js addons', () => {
term.buffer.scrollTop = 1;
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, 'c');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c');
});
it('should properly scroll inside a scroll region (scrollBottom set)', () => {
@@ -558,11 +558,11 @@ describe('term.js addons', () => {
term.buffer.scrollBottom = 3;
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'b');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, 'c');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).chars, 'd');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).chars, '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).chars, 'e');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'b');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'd');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), 'e');
});
it('should properly scroll inside a scroll region (scrollTop and scrollBottom set)', () => {
@@ -576,11 +576,11 @@ describe('term.js addons', () => {
term.buffer.scrollBottom = 3;
term.scroll();
assert.equal(term.buffer.lines.length, INIT_ROWS);
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).chars, 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).chars, 'c', '\'b\' should be removed from the buffer');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).chars, 'd');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).chars, '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).chars, 'e');
assert.equal(term.buffer.lines.get(0).loadCell(0, new CellData()).getChars(), 'a');
assert.equal(term.buffer.lines.get(1).loadCell(0, new CellData()).getChars(), 'c', '\'b\' should be removed from the buffer');
assert.equal(term.buffer.lines.get(2).loadCell(0, new CellData()).getChars(), 'd');
assert.equal(term.buffer.lines.get(3).loadCell(0, new CellData()).getChars(), '', 'a blank line should be added at scrollBottom\'s index');
assert.equal(term.buffer.lines.get(4).loadCell(0, new CellData()).getChars(), 'e');
});
});
});
@@ -775,10 +775,10 @@ describe('term.js addons', () => {
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.write(high + String.fromCharCode(i));
const tchar = term.buffer.lines.get(0).loadCell(0, cell);
expect(tchar.chars).eql(high + String.fromCharCode(i));
expect(tchar.chars.length).eql(2);
expect(tchar.width).eql(1);
expect(term.buffer.lines.get(0).loadCell(1, cell).chars).eql('');
expect(tchar.getChars()).eql(high + String.fromCharCode(i));
expect(tchar.getChars().length).eql(2);
expect(tchar.getWidth()).eql(1);
expect(term.buffer.lines.get(0).loadCell(1, cell).getChars()).eql('');
term.reset();
}
});
@@ -788,9 +788,9 @@ describe('term.js addons', () => {
for (let i = 0xDC00; i <= 0xDCFF; ++i) {
term.buffer.x = term.cols - 1;
term.write(high + String.fromCharCode(i));
expect(term.buffer.lines.get(0).loadCell(term.buffer.x - 1, cell).chars).eql(high + String.fromCharCode(i));
expect(term.buffer.lines.get(0).loadCell(term.buffer.x - 1, cell).chars.length).eql(2);
expect(term.buffer.lines.get(1).loadCell(0, cell).chars).eql('');
expect(term.buffer.lines.get(0).loadCell(term.buffer.x - 1, cell).getChars()).eql(high + String.fromCharCode(i));
expect(term.buffer.lines.get(0).loadCell(term.buffer.x - 1, cell).getChars().length).eql(2);
expect(term.buffer.lines.get(1).loadCell(0, cell).getChars()).eql('');
term.reset();
}
});
@@ -801,10 +801,10 @@ describe('term.js addons', () => {
term.buffer.x = term.cols - 1;
term.wraparoundMode = true;
term.write('a' + high + String.fromCharCode(i));
expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).chars).eql('a');
expect(term.buffer.lines.get(1).loadCell(0, cell).chars).eql(high + String.fromCharCode(i));
expect(term.buffer.lines.get(1).loadCell(0, cell).chars.length).eql(2);
expect(term.buffer.lines.get(1).loadCell(1, cell).chars).eql('');
expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).getChars()).eql('a');
expect(term.buffer.lines.get(1).loadCell(0, cell).getChars()).eql(high + String.fromCharCode(i));
expect(term.buffer.lines.get(1).loadCell(0, cell).getChars().length).eql(2);
expect(term.buffer.lines.get(1).loadCell(1, cell).getChars()).eql('');
term.reset();
}
});
@@ -816,9 +816,9 @@ describe('term.js addons', () => {
term.wraparoundMode = false;
term.write('a' + high + String.fromCharCode(i));
// auto wraparound mode should cut off the rest of the line
expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).chars).eql('a');
expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).chars.length).eql(1);
expect(term.buffer.lines.get(1).loadCell(1, cell).chars).eql('');
expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).getChars()).eql('a');
expect(term.buffer.lines.get(0).loadCell(term.cols - 1, cell).getChars().length).eql(1);
expect(term.buffer.lines.get(1).loadCell(1, cell).getChars()).eql('');
term.reset();
}
});
@@ -829,10 +829,10 @@ describe('term.js addons', () => {
term.write(high);
term.write(String.fromCharCode(i));
const tchar = term.buffer.lines.get(0).loadCell(0, cell);
expect(tchar.chars).eql(high + String.fromCharCode(i));
expect(tchar.chars.length).eql(2);
expect(tchar.width).eql(1);
expect(term.buffer.lines.get(0).loadCell(1, cell).chars).eql('');
expect(tchar.getChars()).eql(high + String.fromCharCode(i));
expect(tchar.getChars().length).eql(2);
expect(tchar.getWidth()).eql(1);
expect(term.buffer.lines.get(0).loadCell(1, cell).getChars()).eql('');
term.reset();
}
});
@@ -843,49 +843,49 @@ describe('term.js addons', () => {
it('café', () => {
term.write('cafe\u0301');
term.buffer.lines.get(0).loadCell(3, cell);
expect(cell.chars).eql('e\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('e\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(1);
});
it('café - end of line', () => {
term.buffer.x = term.cols - 1 - 3;
term.write('cafe\u0301');
term.buffer.lines.get(0).loadCell(term.cols - 1, cell);
expect(cell.chars).eql('e\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('e\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(1);
term.buffer.lines.get(0).loadCell(1, cell);
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(1);
});
it('multiple combined é', () => {
term.wraparoundMode = true;
term.write(Array(100).join('e\u0301'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
expect(cell.chars).eql('e\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('e\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(1);
}
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('e\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('e\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(1);
});
it('multiple surrogate with combined', () => {
term.wraparoundMode = true;
term.write(Array(100).join('\uD800\uDC00\u0301'));
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
expect(cell.chars).eql('\uD800\uDC00\u0301');
expect(cell.chars.length).eql(3);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('\uD800\uDC00\u0301');
expect(cell.getChars().length).eql(3);
expect(cell.getWidth()).eql(1);
}
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('\uD800\uDC00\u0301');
expect(cell.chars.length).eql(3);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('\uD800\uDC00\u0301');
expect(cell.getChars().length).eql(3);
expect(cell.getWidth()).eql(1);
});
});
@@ -908,19 +908,19 @@ describe('term.js addons', () => {
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
if (i % 2) {
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(0);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(0);
} else {
expect(cell.chars).eql('¥');
expect(cell.chars.length).eql(1);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥');
expect(cell.getChars().length).eql(1);
expect(cell.getWidth()).eql(2);
}
}
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('¥');
expect(cell.chars.length).eql(1);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥');
expect(cell.getChars().length).eql(1);
expect(cell.getWidth()).eql(2);
});
it('line of ¥ odd', () => {
term.wraparoundMode = true;
@@ -929,23 +929,23 @@ describe('term.js addons', () => {
for (let i = 1; i < term.cols - 1; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
if (!(i % 2)) {
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(0);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(0);
} else {
expect(cell.chars).eql('¥');
expect(cell.chars.length).eql(1);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥');
expect(cell.getChars().length).eql(1);
expect(cell.getWidth()).eql(2);
}
}
term.buffer.lines.get(0).loadCell(term.cols - 1, cell);
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(1);
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('¥');
expect(cell.chars.length).eql(1);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥');
expect(cell.getChars().length).eql(1);
expect(cell.getWidth()).eql(2);
});
it('line of ¥ with combining odd', () => {
term.wraparoundMode = true;
@@ -954,23 +954,23 @@ describe('term.js addons', () => {
for (let i = 1; i < term.cols - 1; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
if (!(i % 2)) {
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(0);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(0);
} else {
expect(cell.chars).eql('¥\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(2);
}
}
term.buffer.lines.get(0).loadCell(term.cols - 1, cell);
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(1);
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('¥\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(2);
});
it('line of ¥ with combining even', () => {
term.wraparoundMode = true;
@@ -978,19 +978,19 @@ describe('term.js addons', () => {
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
if (i % 2) {
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(0);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(0);
} else {
expect(cell.chars).eql('¥\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(2);
}
}
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('¥\u0301');
expect(cell.chars.length).eql(2);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('¥\u0301');
expect(cell.getChars().length).eql(2);
expect(cell.getWidth()).eql(2);
});
it('line of surrogate fullwidth with combining odd', () => {
term.wraparoundMode = true;
@@ -999,23 +999,23 @@ describe('term.js addons', () => {
for (let i = 1; i < term.cols - 1; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
if (!(i % 2)) {
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(0);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(0);
} else {
expect(cell.chars).eql('\ud843\ude6d\u0301');
expect(cell.chars.length).eql(3);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('\ud843\ude6d\u0301');
expect(cell.getChars().length).eql(3);
expect(cell.getWidth()).eql(2);
}
}
term.buffer.lines.get(0).loadCell(term.cols - 1, cell);
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(1);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(1);
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('\ud843\ude6d\u0301');
expect(cell.chars.length).eql(3);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('\ud843\ude6d\u0301');
expect(cell.getChars().length).eql(3);
expect(cell.getWidth()).eql(2);
});
it('line of surrogate fullwidth with combining even', () => {
term.wraparoundMode = true;
@@ -1023,19 +1023,19 @@ describe('term.js addons', () => {
for (let i = 0; i < term.cols; ++i) {
term.buffer.lines.get(0).loadCell(i, cell);
if (i % 2) {
expect(cell.chars).eql('');
expect(cell.chars.length).eql(0);
expect(cell.width).eql(0);
expect(cell.getChars()).eql('');
expect(cell.getChars().length).eql(0);
expect(cell.getWidth()).eql(0);
} else {
expect(cell.chars).eql('\ud843\ude6d\u0301');
expect(cell.chars.length).eql(3);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('\ud843\ude6d\u0301');
expect(cell.getChars().length).eql(3);
expect(cell.getWidth()).eql(2);
}
}
term.buffer.lines.get(1).loadCell(0, cell);
expect(cell.chars).eql('\ud843\ude6d\u0301');
expect(cell.chars.length).eql(3);
expect(cell.width).eql(2);
expect(cell.getChars()).eql('\ud843\ude6d\u0301');
expect(cell.getChars().length).eql(3);
expect(cell.getWidth()).eql(2);
});
});
@@ -1048,10 +1048,10 @@ describe('term.js addons', () => {
term.insertMode = true;
term.write('abcde');
expect(term.buffer.lines.get(0).length).eql(term.cols);
expect(term.buffer.lines.get(0).loadCell(10, cell).chars).eql('a');
expect(term.buffer.lines.get(0).loadCell(14, cell).chars).eql('e');
expect(term.buffer.lines.get(0).loadCell(15, cell).chars).eql('0');
expect(term.buffer.lines.get(0).loadCell(79, cell).chars).eql('4');
expect(term.buffer.lines.get(0).loadCell(10, cell).getChars()).eql('a');
expect(term.buffer.lines.get(0).loadCell(14, cell).getChars()).eql('e');
expect(term.buffer.lines.get(0).loadCell(15, cell).getChars()).eql('0');
expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql('4');
});
it('fullwidth - insert', () => {
term.write(Array(9).join('0123456789').slice(-80));
@@ -1060,11 +1060,11 @@ describe('term.js addons', () => {
term.insertMode = true;
term.write('¥¥¥');
expect(term.buffer.lines.get(0).length).eql(term.cols);
expect(term.buffer.lines.get(0).loadCell(10, cell).chars).eql('¥');
expect(term.buffer.lines.get(0).loadCell(11, cell).chars).eql('');
expect(term.buffer.lines.get(0).loadCell(14, cell).chars).eql('¥');
expect(term.buffer.lines.get(0).loadCell(15, cell).chars).eql('');
expect(term.buffer.lines.get(0).loadCell(79, cell).chars).eql('3');
expect(term.buffer.lines.get(0).loadCell(10, cell).getChars()).eql('¥');
expect(term.buffer.lines.get(0).loadCell(11, cell).getChars()).eql('');
expect(term.buffer.lines.get(0).loadCell(14, cell).getChars()).eql('¥');
expect(term.buffer.lines.get(0).loadCell(15, cell).getChars()).eql('');
expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql('3');
});
it('fullwidth - right border', () => {
term.write(Array(41).join('¥'));
@@ -1073,14 +1073,14 @@ describe('term.js addons', () => {
term.insertMode = true;
term.write('a');
expect(term.buffer.lines.get(0).length).eql(term.cols);
expect(term.buffer.lines.get(0).loadCell(10, cell).chars).eql('a');
expect(term.buffer.lines.get(0).loadCell(11, cell).chars).eql('¥');
expect(term.buffer.lines.get(0).loadCell(79, cell).chars).eql(''); // fullwidth char got replaced
expect(term.buffer.lines.get(0).loadCell(10, cell).getChars()).eql('a');
expect(term.buffer.lines.get(0).loadCell(11, cell).getChars()).eql('¥');
expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql(''); // fullwidth char got replaced
term.write('b');
expect(term.buffer.lines.get(0).length).eql(term.cols);
expect(term.buffer.lines.get(0).loadCell(11, cell).chars).eql('b');
expect(term.buffer.lines.get(0).loadCell(12, cell).chars).eql('¥');
expect(term.buffer.lines.get(0).loadCell(79, cell).chars).eql(''); // empty cell after fullwidth
expect(term.buffer.lines.get(0).loadCell(11, cell).getChars()).eql('b');
expect(term.buffer.lines.get(0).loadCell(12, cell).getChars()).eql('¥');
expect(term.buffer.lines.get(0).loadCell(79, cell).getChars()).eql(''); // empty cell after fullwidth
});
});
});
+5 -5
View File
@@ -528,12 +528,12 @@ export interface ICellData {
fg: number;
bg: number;
combinedData: string;
isCombined: number;
width: number;
chars: string;
code: number;
isCombined(): number;
getWidth(): number;
getChars(): string;
getCode(): number;
setFromCharData(value: CharData): void;
asCharData: CharData;
getAsCharData(): CharData;
}
/**
+1 -1
View File
@@ -239,7 +239,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
this._ctx.textBaseline = 'middle';
this._clipRow(terminal, y);
this._ctx.fillText(
cell.chars,
cell.getChars(),
x * this._scaledCellWidth + this._scaledCharLeft,
(y + 0.5) * this._scaledCellHeight + this._scaledCharTop);
}
+2 -2
View File
@@ -56,8 +56,8 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
for (let x = 0; x < this._terminal.cols; x++) {
line.loadCell(x, this._cell);
const chars = this._cell.chars;
const width = this._cell.width;
const chars = this._cell.getChars();
const width = this._cell.getWidth();
const attr = this._cell.fg >> 9;
if (width === 0) {
+5 -5
View File
@@ -143,7 +143,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
this._state.y = viewportRelativeCursorY;
this._state.isFocused = false;
this._state.style = terminal.options.cursorStyle;
this._state.width = this._cell.width;
this._state.width = this._cell.getWidth();
return;
}
@@ -159,7 +159,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
this._state.y === viewportRelativeCursorY &&
this._state.isFocused === terminal.isFocused &&
this._state.style === terminal.options.cursorStyle &&
this._state.width === this._cell.width) {
this._state.width === this._cell.getWidth()) {
return;
}
this._clearCursor();
@@ -173,7 +173,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
this._state.y = viewportRelativeCursorY;
this._state.isFocused = false;
this._state.style = terminal.options.cursorStyle;
this._state.width = this._cell.width;
this._state.width = this._cell.getWidth();
}
private _clearCursor(): void {
@@ -199,7 +199,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
private _renderBlockCursor(terminal: ITerminal, x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this.fillCells(x, y, cell.width, 1);
this.fillCells(x, y, cell.getWidth(), 1);
this._ctx.fillStyle = this._colors.cursorAccent.css;
this.fillCharTrueColor(terminal, cell, x, y);
this._ctx.restore();
@@ -215,7 +215,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
private _renderBlurCursor(terminal: ITerminal, x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.strokeStyle = this._colors.cursor.css;
this.strokeRectAtCell(x, y, cell.width, 1);
this.strokeRectAtCell(x, y, cell.getWidth(), 1);
this._ctx.restore();
}
}
+4 -4
View File
@@ -75,13 +75,13 @@ export class TextRenderLayer extends BaseRenderLayer {
const joinedRanges = joinerRegistry ? joinerRegistry.getJoinedCharacters(row) : [];
for (let x = 0; x < terminal.cols; x++) {
(line as any).loadCell(x, this._cell);
let code: number = this._cell.code || WHITESPACE_CELL_CODE;
let code: number = this._cell.getCode() || WHITESPACE_CELL_CODE;
// Can either represent character(s) for a single cell or multiple cells
// if indicated by a character joiner.
let chars = this._cell.chars || WHITESPACE_CELL_CHAR;
let chars = this._cell.getChars() || WHITESPACE_CELL_CHAR;
const attr = this._cell.fg;
let width = this._cell.width;
let width = this._cell.getWidth();
// If true, indicates that the current character(s) to draw were joined.
let isJoined = false;
@@ -127,7 +127,7 @@ export class TextRenderLayer extends BaseRenderLayer {
// get removed, and `a` would not re-render because it thinks it's
// already in the correct state.
// this._state.cache[x][y] = OVERLAP_OWNED_CHAR_DATA;
if (lastCharX < line.length - 1 && line.loadCell(lastCharX + 1, this._cell).code === NULL_CELL_CODE) {
if (lastCharX < line.length - 1 && line.loadCell(lastCharX + 1, this._cell).getCode() === NULL_CELL_CODE) {
width = 2;
// this._clearChar(x + 1, y);
// The overlapping char's char data will force a clear and render when the
+3 -3
View File
@@ -33,7 +33,7 @@ export class DomRendererRowFactory {
// the viewport).
let lineLength = 0;
for (let x = Math.min(lineData.length, cols) - 1; x >= 0; x--) {
if (lineData.loadCell(x, this._cell).code !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) {
if (lineData.loadCell(x, this._cell).getCode() !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) {
lineLength = x + 1;
break;
}
@@ -42,7 +42,7 @@ export class DomRendererRowFactory {
for (let x = 0; x < lineLength; x++) {
lineData.loadCell(x, this._cell);
const attr = this._cell.fg;
const width = this._cell.width;
const width = this._cell.getWidth();
// The character to the left is a wide character, drawing is owned by the char at x-1
if (width === 0) {
@@ -100,7 +100,7 @@ export class DomRendererRowFactory {
charElement.classList.add(ITALIC_CLASS);
}
charElement.textContent = this._cell.chars || WHITESPACE_CELL_CHAR;
charElement.textContent = this._cell.getChars() || WHITESPACE_CELL_CHAR;
if (fg !== DEFAULT_COLOR) {
charElement.classList.add(`xterm-fg-${fg}`);
}