Skip to content

Instantly share code, notes, and snippets.

@jerch
Created August 28, 2019 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jerch/cfe4360e7f23df8bc7189c3761bd13f5 to your computer and use it in GitHub Desktop.
Save jerch/cfe4360e7f23df8bc7189c3761bd13f5 to your computer and use it in GitHub Desktop.
import { Terminal, ITerminalAddon, IBufferCell } from 'xterm';
export class SerializeAddon implements ITerminalAddon {
private _terminal: Terminal|undefined = undefined;
public dispose(): void {}
public activate(terminal: Terminal): void {
this._terminal = terminal;
}
private _extractAttributes(oldCell: IBufferCell, newCell: IBufferCell): string {
if (oldCell.equalAttibutes(newCell)) {
return '';
}
const switches: number[] = [];
// flags
if (!oldCell.equalFlags(newCell)) {
if (oldCell.flags.bold !== newCell.flags.bold) switches.push(newCell.flags.bold ? 1 : 22);
if (oldCell.flags.underline !== newCell.flags.underline) switches.push(newCell.flags.underline ? 4 : 24);
if (oldCell.flags.inverse !== newCell.flags.inverse) switches.push(newCell.flags.inverse ? 7 : 27);
if (oldCell.flags.invisible !== newCell.flags.invisible) switches.push(newCell.flags.invisible ? 8 : 28);
if (oldCell.flags.blink !== newCell.flags.blink) switches.push(newCell.flags.blink ? 5 : 25);
if (oldCell.flags.italic !== newCell.flags.italic) switches.push(newCell.flags.italic ? 3 : 23);
if (oldCell.flags.dim !== newCell.flags.dim) switches.push(newCell.flags.dim ? 2 : 22);
}
// colors
if (!oldCell.equalFg(newCell)) {
switch (newCell.fg.colorMode) {
case 'RGB':
switches.push(38);
switches.push(2);
switches.push((newCell.fg.color >> 16) & 0xFF);
switches.push((newCell.fg.color >> 8) & 0xFF);
switches.push(newCell.fg.color & 0xFF);
break;
case 'P256':
switches.push(38);
switches.push(5);
switches.push(newCell.fg.color);
break;
case 'P16':
switches.push(newCell.fg.color & 8 ? 90 + (newCell.fg.color & 7) : 30 + (newCell.fg.color & 7));
break;
default:
switches.push(39);
}
}
if (!oldCell.equalBg(newCell)) {
switch (newCell.bg.colorMode) {
case 'RGB':
switches.push(48);
switches.push(2);
switches.push((newCell.bg.color >> 16) & 0xFF);
switches.push((newCell.bg.color >> 8) & 0xFF);
switches.push(newCell.bg.color & 0xFF);
break;
case 'P256':
switches.push(48);
switches.push(5);
switches.push(newCell.bg.color);
break;
case 'P16':
switches.push(newCell.bg.color & 8 ? 100 + (newCell.bg.color & 7) : 40 + (newCell.bg.color & 7));
break;
default:
switches.push(49);
}
}
if (switches.length) {
return `\x1b[${switches.join(';')}m`;
}
return '';
}
public serialize(): string {
if (!this._terminal) {
return '';
}
// cells for ref style usage
// we need two of them to flip between old and new cell
const cell1 = this._terminal.buffer.getNullCell();
const cell2 = this._terminal.buffer.getNullCell();
let oldCell = cell1;
const result: string[] = [];
const end = this._terminal.buffer.length;
for (let y = 0; y < end; ++y) {
const sLine: string[] = [];
const line = this._terminal.buffer.getLine(y);
if (!line) {
continue;
}
const length = this._terminal.cols;
for (let x = 0; x < length;) {
const newCell = line.getCell(x, oldCell === cell1 ? cell2 : cell1);
if (!newCell) {
continue;
}
const diff = this._extractAttributes(oldCell, newCell);
if (diff) {
sLine.push(diff);
oldCell = newCell;
}
sLine.push(newCell.char || ' ');
x += newCell.width || 1; // always advance by 1!
}
result.push(sLine.join(''));
}
return result.join('\r\n');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment