diff --git a/src/Buffer.ts b/src/Buffer.ts index e54f752b..7c5d2652 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -16,9 +16,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_WIDTH = 1; -export const NULL_CELL_CODE = 32; +// export const NULL_CELL_CHAR = ' '; +// export const NULL_CELL_WIDTH = 1; +// export const NULL_CELL_CODE = 32; + +export const NULL_CELL_CHAR = ''; +export const NULL_CELL_WIDTH = 0; +export const NULL_CELL_CODE = 0; /** * This class represents a terminal buffer (an internal state of the terminal), where the @@ -273,6 +277,7 @@ export class Buffer implements IBuffer { if (!line) { return ''; } + return line.translateToString(trimRight, startCol, endCol); // Initialize column and index values. Column values represent the actual // cell column, indexes represent the index in the string. Indexes are diff --git a/src/BufferLine.ts b/src/BufferLine.ts index f1ea9cf0..e1cb6a4f 100644 --- a/src/BufferLine.ts +++ b/src/BufferLine.ts @@ -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 } from './Buffer'; /** * Class representing a terminal line. @@ -108,6 +108,27 @@ export class BufferLine 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] - 1; + } + } + 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 = ''; + for (let i = startCol; i < length; ++i) { + result += this.get(i)[CHAR_DATA_CHAR_INDEX] || ' '; + } + return result; + } } /** typed array slots taken by one cell */ @@ -279,4 +300,25 @@ export class BufferLineTypedArray 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 + 1; + } + } + 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 = ''; + for (let i = startCol; i < length; ++i) { + const stringData = this._data[i * CELL_SIZE + Cell.STRING]; + result += (stringData & 0x80000000) ? this._combined[i] : (stringData) ? String.fromCharCode(stringData) : ' '; + } + return result; + } } diff --git a/src/Terminal.integration.ts b/src/Terminal.integration.ts index 66fd3502..21c4a2d0 100644 --- a/src/Terminal.integration.ts +++ b/src/Terminal.integration.ts @@ -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] || ' '; } // rtrim empty cells as xterm does lineText = lineText.replace(/\s+$/, ''); diff --git a/src/Types.ts b/src/Types.ts index e8578426..b0ccf88d 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -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 {