mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
add frontground/background color support for SerializeAddon
This commit is contained in:
@@ -21,6 +21,7 @@ describe('SerializeAddon', () => {
|
||||
browser = await puppeteer.launch({
|
||||
headless: process.argv.indexOf('--headless') !== -1,
|
||||
slowMo: 80,
|
||||
devtools: true,
|
||||
args: [`--window-size=${width},${height}`]
|
||||
});
|
||||
page = (await browser.pages())[0];
|
||||
@@ -40,8 +41,7 @@ describe('SerializeAddon', () => {
|
||||
this.timeout(20000);
|
||||
const rows = 10;
|
||||
const cols = 10;
|
||||
const blankline = ' '.repeat(cols);
|
||||
const lines = newArray<string>(blankline, rows);
|
||||
const lines = newArray<string>('', rows);
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
@@ -69,7 +69,7 @@ describe('SerializeAddon', () => {
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize n rows of content', async function (): Promise<any> {
|
||||
it('serialize half rows of content', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const rows = 10;
|
||||
const halfRows = rows >> 1;
|
||||
@@ -101,6 +101,254 @@ describe('SerializeAddon', () => {
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize(0);`), '');
|
||||
});
|
||||
|
||||
it('serialize all rows of content with color16', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const rows = 16;
|
||||
const cols = 10;
|
||||
const color16 = [
|
||||
30, 31, 32, 33, 34, 35, 36, 37, // Set foreground color
|
||||
40, 41, 42, 43, 44, 45, 46, 47 // Set background color
|
||||
];
|
||||
const lines = newArray<string>(
|
||||
(index: number) => digitsString(cols, index, `\x1b[${color16[index % color16.length]}m`),
|
||||
rows
|
||||
);
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with fg/bg flags', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_P16_GREEN) + line, // Workaround: If we clear all flags a the end, serialize will use \x1b[0m to clear instead of the sepcific disable sequence
|
||||
mkSGR(INVERSE) + line,
|
||||
mkSGR(BOLD) + line,
|
||||
mkSGR(UNDERLINED) + line,
|
||||
mkSGR(BLINK) + line,
|
||||
mkSGR(INVISIBLE) + line,
|
||||
mkSGR(NO_INVERSE) + line,
|
||||
mkSGR(NO_BOLD) + line,
|
||||
mkSGR(NO_UNDERLINED) + line,
|
||||
mkSGR(NO_BLINK) + line,
|
||||
mkSGR(NO_INVISIBLE) + line
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with color256', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const rows = 32;
|
||||
const cols = 10;
|
||||
const lines = newArray<string>(
|
||||
(index: number) => digitsString(cols, index, `\x1b[38;5;${index}m`),
|
||||
rows
|
||||
);
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with color16 and style separately', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_P16_RED) + line, // fg Red,
|
||||
mkSGR(UNDERLINED) + line, // fg Red, Underlined
|
||||
mkSGR(FG_P16_GREEN) + line, // fg Green, Underlined
|
||||
mkSGR(INVERSE) + line, // fg Green, Underlined, Inverse
|
||||
mkSGR(NO_INVERSE) + line, // fg Green, Underlined
|
||||
mkSGR(INVERSE) + line, // fg Green, Underlined, Inverse
|
||||
mkSGR(BG_P16_YELLOW) + line, // fg Green, bg Yellow, Underlined, Inverse
|
||||
mkSGR(FG_RESET) + line, // bg Yellow, Underlined, Inverse
|
||||
mkSGR(BG_RESET) + line, // Underlined, Inverse
|
||||
mkSGR(NORMAL) + line // Back to normal
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with color16 and style together', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_P16_RED) + line, // fg Red
|
||||
mkSGR(FG_P16_GREEN, BG_P16_YELLOW) + line, // fg Green, bg Yellow
|
||||
mkSGR(UNDERLINED, ITALIC) + line, // fg Green, bg Yellow, Underlined, Italic
|
||||
mkSGR(NO_UNDERLINED, NO_ITALIC) + line, // fg Green, bg Yellow
|
||||
mkSGR(FG_RESET, ITALIC) + line, // bg Yellow, Italic
|
||||
mkSGR(BG_RESET) + line, // Italic
|
||||
mkSGR(NORMAL) + line, // Back to normal
|
||||
mkSGR(FG_P16_RED) + line, // fg Red
|
||||
mkSGR(FG_P16_GREEN, BG_P16_YELLOW) + line, // fg Green, bg Yellow
|
||||
mkSGR(UNDERLINED, ITALIC) + line, // fg Green, bg Yellow, Underlined, Italic
|
||||
mkSGR(NO_UNDERLINED, NO_ITALIC) + line, // fg Green, bg Yellow
|
||||
mkSGR(FG_RESET, ITALIC) + line, // bg Yellow, Italic
|
||||
mkSGR(BG_RESET) + line // Italic
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with color256 and style separately', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_P256_RED) + line, // fg Red 256,
|
||||
mkSGR(UNDERLINED) + line, // fg Red 256, Underlined
|
||||
mkSGR(FG_P256_GREEN) + line, // fg Green 256, Underlined
|
||||
mkSGR(INVERSE) + line, // fg Green 256, Underlined, Inverse
|
||||
mkSGR(NO_INVERSE) + line, // fg Green 256, Underlined
|
||||
mkSGR(INVERSE) + line, // fg Green 256, Underlined, Inverse
|
||||
mkSGR(BG_P256_YELLOW) + line, // fg Green 256, bg Yellow 256, Underlined, Inverse
|
||||
mkSGR(FG_RESET) + line, // bg Yellow 256, Underlined, Inverse
|
||||
mkSGR(BG_RESET) + line, // Underlined, Inverse
|
||||
mkSGR(NORMAL) + line // Back to normal
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with color256 and style together', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_P256_RED) + line, // fg Red 256
|
||||
mkSGR(FG_P256_GREEN, BG_P256_YELLOW) + line, // fg Green 256, bg Yellow 256
|
||||
mkSGR(UNDERLINED, ITALIC) + line, // fg Green 256, bg Yellow 256, Underlined, Italic
|
||||
mkSGR(NO_UNDERLINED, NO_ITALIC) + line, // fg Green 256, bg Yellow 256
|
||||
mkSGR(FG_RESET, ITALIC) + line, // bg Yellow 256, Italic
|
||||
mkSGR(BG_RESET) + line, // Italic
|
||||
mkSGR(NORMAL) + line, // Back to normal
|
||||
mkSGR(FG_P256_RED) + line, // fg Red 256
|
||||
mkSGR(FG_P256_GREEN, BG_P256_YELLOW) + line, // fg Green 256, bg Yellow 256
|
||||
mkSGR(UNDERLINED, ITALIC) + line, // fg Green 256, bg Yellow 256, Underlined, Italic
|
||||
mkSGR(NO_UNDERLINED, NO_ITALIC) + line, // fg Green 256, bg Yellow 256
|
||||
mkSGR(FG_RESET, ITALIC) + line, // bg Yellow 256, Italic
|
||||
mkSGR(BG_RESET) + line // Italic
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with colorRGB and style separately', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_RGB_RED) + line, // fg Red RGB,
|
||||
mkSGR(UNDERLINED) + line, // fg Red RGB, Underlined
|
||||
mkSGR(FG_RGB_GREEN) + line, // fg Green RGB, Underlined
|
||||
mkSGR(INVERSE) + line, // fg Green RGB, Underlined, Inverse
|
||||
mkSGR(NO_INVERSE) + line, // fg Green RGB, Underlined
|
||||
mkSGR(INVERSE) + line, // fg Green RGB, Underlined, Inverse
|
||||
mkSGR(BG_RGB_YELLOW) + line, // fg Green RGB, bg Yellow RGB, Underlined, Inverse
|
||||
mkSGR(FG_RESET) + line, // bg Yellow RGB, Underlined, Inverse
|
||||
mkSGR(BG_RESET) + line, // Underlined, Inverse
|
||||
mkSGR(NORMAL) + line // Back to normal
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
|
||||
it('serialize all rows of content with colorRGB and style together', async function (): Promise<any> {
|
||||
this.timeout(20000);
|
||||
const cols = 10;
|
||||
const line = '+'.repeat(cols);
|
||||
const lines: string[] = [
|
||||
mkSGR(FG_RGB_RED) + line, // fg Red RGB
|
||||
mkSGR(FG_RGB_GREEN, BG_RGB_YELLOW) + line, // fg Green RGB, bg Yellow RGB
|
||||
mkSGR(UNDERLINED, ITALIC) + line, // fg Green RGB, bg Yellow RGB, Underlined, Italic
|
||||
mkSGR(NO_UNDERLINED, NO_ITALIC) + line, // fg Green RGB, bg Yellow RGB
|
||||
mkSGR(FG_RESET, ITALIC) + line, // bg Yellow RGB, Italic
|
||||
mkSGR(BG_RESET) + line, // Italic
|
||||
mkSGR(NORMAL) + line, // Back to normal
|
||||
mkSGR(FG_RGB_RED) + line, // fg Red RGB
|
||||
mkSGR(FG_RGB_GREEN, BG_RGB_YELLOW) + line, // fg Green RGB, bg Yellow RGB
|
||||
mkSGR(UNDERLINED, ITALIC) + line, // fg Green RGB, bg Yellow RGB, Underlined, Italic
|
||||
mkSGR(NO_UNDERLINED, NO_ITALIC) + line, // fg Green RGB, bg Yellow RGB
|
||||
mkSGR(FG_RESET, ITALIC) + line, // bg Yellow RGB, Italic
|
||||
mkSGR(BG_RESET) + line // Italic
|
||||
];
|
||||
const rows = lines.length;
|
||||
|
||||
await openTerminal({ rows: rows, cols: cols, rendererType: 'dom' });
|
||||
await page.evaluate(`
|
||||
window.serializeAddon = new SerializeAddon();
|
||||
window.term.loadAddon(window.serializeAddon);
|
||||
window.term.write(${util.inspect(lines.join('\r\n'))});
|
||||
`);
|
||||
|
||||
assert.equal(await page.evaluate(`serializeAddon.serialize();`), lines.join('\r\n'));
|
||||
});
|
||||
});
|
||||
|
||||
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
|
||||
@@ -125,10 +373,57 @@ function newArray<T>(initial: T | ((index: number) => T), count: number): T[] {
|
||||
return array;
|
||||
}
|
||||
|
||||
function digitsString(length: number, from: number = 0): string {
|
||||
let s = '';
|
||||
function digitsString(length: number, from: number = 0, sgr: string = ''): string {
|
||||
let s = sgr;
|
||||
for (let i = 0; i < length; i++) {
|
||||
s += (from++) % 10;
|
||||
s += `${(from++) % 10}`;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function mkSGR(...seq: string[]): string {
|
||||
return `\x1b[${seq.join(';')}m`;
|
||||
}
|
||||
|
||||
const NORMAL = '0';
|
||||
|
||||
const FG_P16_RED = '31';
|
||||
const FG_P16_GREEN = '32';
|
||||
const FG_P16_YELLOW = '33';
|
||||
const FG_P256_RED = '38;5;1';
|
||||
const FG_P256_GREEN = '38;5;2';
|
||||
const FG_P256_YELLOW = '38;5;3';
|
||||
const FG_RGB_RED = '38;2;255;0;0';
|
||||
const FG_RGB_GREEN = '38;2;0;255;0';
|
||||
const FG_RGB_YELLOW = '38;2;255;255;0';
|
||||
const FG_RESET = '39';
|
||||
|
||||
|
||||
const BG_P16_RED = '41';
|
||||
const BG_P16_GREEN = '42';
|
||||
const BG_P16_YELLOW = '43';
|
||||
const BG_P256_RED = '48;5;1';
|
||||
const BG_P256_GREEN = '48;5;2';
|
||||
const BG_P256_YELLOW = '48;5;3';
|
||||
const BG_RGB_RED = '48;2;255;0;0';
|
||||
const BG_RGB_GREEN = '48;2;0;255;0';
|
||||
const BG_RGB_YELLOW = '48;2;255;255;0';
|
||||
const BG_RESET = '49';
|
||||
|
||||
const INVERSE = '7';
|
||||
const BOLD = '1';
|
||||
const UNDERLINED = '4';
|
||||
const BLINK = '5';
|
||||
const INVISIBLE = '8';
|
||||
|
||||
const NO_INVERSE = '27';
|
||||
const NO_BOLD = '22';
|
||||
const NO_UNDERLINED = '24';
|
||||
const NO_BLINK = '25';
|
||||
const NO_INVISIBLE = '28';
|
||||
|
||||
const ITALIC = '3';
|
||||
const DIM = '2';
|
||||
|
||||
const NO_ITALIC = '23';
|
||||
const NO_DIM = '22';
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
*/
|
||||
|
||||
import { Terminal, ITerminalAddon } from 'xterm';
|
||||
// import { IBufferLine } from 'common/Types';
|
||||
import { ICellData } from 'common/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { IBuffer } from 'common/buffer/Types';
|
||||
import { Attributes, FgFlags, BgFlags } from 'common/buffer/Constants';
|
||||
|
||||
function crop(value: number | undefined, low: number, high: number, initial: number): number {
|
||||
if (value === undefined) {
|
||||
@@ -14,20 +16,184 @@ function crop(value: number | undefined, low: number, high: number, initial: num
|
||||
return Math.max(low, Math.min(value, high));
|
||||
}
|
||||
|
||||
class SerializeHandler {
|
||||
class BaseSerializeHandler {
|
||||
constructor(private _buffer: IBuffer) { }
|
||||
|
||||
serialize(start: number, end: number): string {
|
||||
const rows = end - start;
|
||||
const lines: string[] = new Array<string>(rows);
|
||||
serialize(startRow: number, endRow: number): string {
|
||||
let oldCell = new CellData();
|
||||
|
||||
for (let i = start; i < end; i++) {
|
||||
const line = this._buffer.lines.get(i);
|
||||
this._serializeStart(endRow - startRow);
|
||||
|
||||
lines[i - start] = line ? line.translateToString() : '';
|
||||
for (let row = startRow; row < endRow; row++) {
|
||||
const line = this._buffer.lines.get(row);
|
||||
|
||||
this._lineStart(row);
|
||||
|
||||
if (line) {
|
||||
for (let col = 0; col < line.length; col++) {
|
||||
const cell = new CellData();
|
||||
|
||||
line.loadCell(col, cell);
|
||||
|
||||
if (oldCell.fg !== cell.fg) {
|
||||
this._fgChanged(cell, oldCell, row, col);
|
||||
}
|
||||
if (oldCell.bg !== cell.bg) {
|
||||
this._bgChanged(cell, oldCell, row, col);
|
||||
}
|
||||
|
||||
this._cellChanged(cell, oldCell, row, col);
|
||||
|
||||
oldCell = cell;
|
||||
}
|
||||
}
|
||||
|
||||
this._lineEnd(row);
|
||||
}
|
||||
|
||||
return lines.join('\r\n');
|
||||
this._serializeEnd();
|
||||
|
||||
return this._serializeFinished();
|
||||
}
|
||||
|
||||
protected _cellChanged(cell: ICellData, oldCell: ICellData, row: number, col: number): void { }
|
||||
|
||||
protected _fgChanged(cell: ICellData, oldCell: ICellData, row: number, col: number): void { }
|
||||
|
||||
protected _bgChanged(cell: ICellData, oldCell: ICellData, row: number, col: number): void { }
|
||||
|
||||
protected _lineStart(row: number): void { }
|
||||
|
||||
protected _lineEnd(row: number): void { }
|
||||
|
||||
protected _serializeStart(rows: number): void { }
|
||||
|
||||
protected _serializeEnd(): void { }
|
||||
|
||||
protected _serializeFinished(): string { return ''; }
|
||||
}
|
||||
|
||||
const FG_FM_MASK = FgFlags.FM_MASK;
|
||||
const BG_FM_MASK = BgFlags.FM_MASK;
|
||||
const COLOR_MASK = Attributes.CM_MASK | Attributes.RGB_MASK;
|
||||
|
||||
class StringSerializeHandler extends BaseSerializeHandler {
|
||||
private _rowIndex: number = 0;
|
||||
private _allRows: string[] = new Array<string>();
|
||||
private _currentRow: string = '';
|
||||
private _sgrSeq: string[] = [];
|
||||
|
||||
constructor(buffer: IBuffer) {
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
protected _serializeStart(rows: number): void {
|
||||
this._allRows = new Array<string>(rows);
|
||||
}
|
||||
|
||||
protected _lineEnd(row: number): void {
|
||||
this._allRows[this._rowIndex++] = this._currentRow;
|
||||
this._currentRow = '';
|
||||
}
|
||||
|
||||
protected _fgChanged(cell: ICellData, oldCell: ICellData, row: number, col: number): void {
|
||||
const fgFlagsChanged = (cell.fg ^ oldCell.fg) & FG_FM_MASK;
|
||||
const fgColorChanged = (cell.fg ^ oldCell.fg) & COLOR_MASK;
|
||||
const sgrSeq = this._sgrSeq;
|
||||
|
||||
if ((cell.fg === 0) && (cell.bg === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fgFlagsChanged) {
|
||||
if (fgFlagsChanged & FgFlags.INVERSE) {
|
||||
sgrSeq.push(cell.isInverse() ? '7' : '27');
|
||||
}
|
||||
if (fgFlagsChanged & FgFlags.BOLD) {
|
||||
sgrSeq.push(cell.isBold() ? '1' : '22');
|
||||
}
|
||||
if (fgFlagsChanged & FgFlags.UNDERLINE) {
|
||||
sgrSeq.push(cell.isUnderline() ? '4' : '24');
|
||||
}
|
||||
if (fgFlagsChanged & FgFlags.BLINK) {
|
||||
sgrSeq.push(cell.isBlink() ? '5' : '25');
|
||||
}
|
||||
if (fgFlagsChanged & FgFlags.INVISIBLE) {
|
||||
sgrSeq.push(cell.isInvisible() ? '8' : '28');
|
||||
}
|
||||
}
|
||||
|
||||
if (fgColorChanged) {
|
||||
const fgColor = cell.getFgColor();
|
||||
|
||||
if (cell.isFgDefault()) {
|
||||
sgrSeq.push('39');
|
||||
} else if (cell.isFgPalette()) {
|
||||
switch (cell.getFgColorMode()) {
|
||||
case Attributes.CM_P16: sgrSeq.push(`${30 + fgColor}`); break;
|
||||
case Attributes.CM_P256: sgrSeq.push(`38;5;${fgColor}`); break;
|
||||
}
|
||||
} else if (cell.isFgRGB()) {
|
||||
const [r, g, b] = CellData.toColorRGB(fgColor);
|
||||
sgrSeq.push(`38;2;${r};${g};${b}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _bgChanged(cell: ICellData, oldCell: ICellData, row: number, col: number): void {
|
||||
const bgFlagsChanged = (cell.bg ^ oldCell.bg) & BG_FM_MASK;
|
||||
const bgColorChanged = (cell.bg ^ oldCell.bg) & COLOR_MASK;
|
||||
const sgrSeq = this._sgrSeq;
|
||||
|
||||
if ((cell.bg === 0) && (cell.fg === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bgFlagsChanged) {
|
||||
if (bgFlagsChanged & BgFlags.ITALIC) {
|
||||
sgrSeq.push(cell.isItalic() ? '3' : '23');
|
||||
}
|
||||
if (bgFlagsChanged & BgFlags.DIM) {
|
||||
sgrSeq.push(cell.isDim() ? '2' : '22');
|
||||
}
|
||||
}
|
||||
|
||||
if (bgColorChanged) {
|
||||
const bgColor = cell.getBgColor();
|
||||
|
||||
if (cell.isBgDefault()) {
|
||||
sgrSeq.push('49');
|
||||
} else if (cell.isBgPalette()) {
|
||||
switch (cell.getBgColorMode()) {
|
||||
case Attributes.CM_P16: sgrSeq.push(`${40 + bgColor}`); break;
|
||||
case Attributes.CM_P256: sgrSeq.push(`48;5;${bgColor}`); break;
|
||||
}
|
||||
} else if (cell.isFgRGB()) {
|
||||
const [r, g, b] = CellData.toColorRGB(bgColor);
|
||||
sgrSeq.push(`48;2;${r};${g};${b}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _cellChanged(cell: ICellData, oldCell: ICellData, row: number, col: number): void {
|
||||
const fgChanged = cell.fg !== oldCell.fg;
|
||||
const bgChanged = cell.bg !== oldCell.bg;
|
||||
const isfgBgNormal = (cell.fg === 0) && (cell.bg === 0);
|
||||
|
||||
if ((fgChanged || bgChanged) && isfgBgNormal) {
|
||||
this._currentRow += '\x1b[0m';
|
||||
}
|
||||
|
||||
if (this._sgrSeq.length) {
|
||||
this._currentRow += `\x1b[${this._sgrSeq.join(';')}m`;
|
||||
this._sgrSeq = [];
|
||||
}
|
||||
|
||||
this._currentRow += cell.getChars();
|
||||
}
|
||||
|
||||
protected _serializeFinished(): string {
|
||||
return this._allRows.join('\r\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,13 +207,15 @@ export class SerializeAddon implements ITerminalAddon {
|
||||
}
|
||||
|
||||
public serialize(rows?: number): string {
|
||||
// TODO: Add frontground/background color support later
|
||||
// TODO: Add re-position cursor support
|
||||
// TODO: Add word wrap mode support
|
||||
// TODO: Add combinedData support
|
||||
if (!this._terminal) {
|
||||
throw new Error('Cannot use addon until it has been loaded');
|
||||
}
|
||||
|
||||
const maxRows = this._terminal.rows;
|
||||
const handler = new SerializeHandler((<any>this._terminal)._core.buffer);
|
||||
const handler = new StringSerializeHandler((<any>this._terminal)._core.buffer);
|
||||
|
||||
rows = crop(rows, 0, maxRows, maxRows);
|
||||
|
||||
|
||||
@@ -116,7 +116,12 @@ export const enum FgFlags {
|
||||
BOLD = 0x8000000,
|
||||
UNDERLINE = 0x10000000,
|
||||
BLINK = 0x20000000,
|
||||
INVISIBLE = 0x40000000
|
||||
INVISIBLE = 0x40000000,
|
||||
|
||||
/**
|
||||
* bit 27..31 (32th bit unused)
|
||||
*/
|
||||
FM_MASK = 0x7C000000
|
||||
}
|
||||
|
||||
export const enum BgFlags {
|
||||
@@ -124,5 +129,10 @@ export const enum BgFlags {
|
||||
* bit 27..32 (upper 4 unused)
|
||||
*/
|
||||
ITALIC = 0x4000000,
|
||||
DIM = 0x8000000
|
||||
DIM = 0x8000000,
|
||||
|
||||
/**
|
||||
* bit 27..32 (upper 4 unused)
|
||||
*/
|
||||
FM_MASK = 0xFC000000
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user