diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index 0332477f..b5d6e08d 100644 --- a/addons/xterm-addon-serialize/src/SerializeAddon.ts +++ b/addons/xterm-addon-serialize/src/SerializeAddon.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { Terminal, ITerminalAddon, IBuffer, IBufferCell, Color } from 'xterm'; +import { Terminal, ITerminalAddon, IBuffer, IBufferCell, CellColor } from 'xterm'; // TODO: Workaround here, will remove this later // If I use `import { CellStyle } from 'xterm'` instead, demo page will raise bellow error @@ -38,8 +38,8 @@ function crop(value: number | undefined, low: number, high: number, initial: num class NullBufferCell implements IBufferCell { char: string = ''; width: number = 0; - foregroundColor: Color = { type: 'default', hash: 0 }; - backgroundColor: Color = { type: 'default', hash: 0 } + foregroundColor: CellColor = CellColor.getDefault(); + backgroundColor: CellColor = CellColor.getDefault(); style: CellStyle = CellStyle.default; } @@ -64,8 +64,8 @@ abstract class BaseSerializeHandler { console.warn(`Can't get cell at row=${row}, col=${col}`); continue; } - if ((cell.foregroundColor.hash !== oldCell.foregroundColor.hash) - || (cell.backgroundColor.hash !== oldCell.backgroundColor.hash)) { + if (!cell.foregroundColor.equals(oldCell.foregroundColor) + || !cell.backgroundColor.equals(oldCell.backgroundColor)) { this._cellColorChanged(cell, oldCell, row, col); } if (cell.style !== oldCell.style) { @@ -122,7 +122,7 @@ function bgColor256to16(c: number): number { } function isDefaultColorStyle(cell: IBufferCell) { - return (cell.foregroundColor.hash === 0) && (cell.backgroundColor.hash === 0) && (cell.style === CellStyle.default); + return cell.foregroundColor.isDefault() && cell.backgroundColor.isDefault() && (cell.style === CellStyle.default); } class StringSerializeHandler extends BaseSerializeHandler { @@ -178,8 +178,8 @@ class StringSerializeHandler extends BaseSerializeHandler { } protected _cellColorChanged(cell: IBufferCell, oldCell: IBufferCell, row: number, col: number): void { - const foregroundColorChanged = cell.foregroundColor.hash !== oldCell.foregroundColor.hash; - const backgroundColorChanged = cell.backgroundColor.hash !== oldCell.backgroundColor.hash; + const foregroundColorChanged = !cell.foregroundColor.equals(oldCell.foregroundColor); + const backgroundColorChanged = !cell.backgroundColor.equals(oldCell.backgroundColor); const sgrSeq = this._sgrSeq; // skip if it's default color style, we will use \x1b[0m to clear every color style later @@ -191,9 +191,9 @@ class StringSerializeHandler extends BaseSerializeHandler { const foregroundColor = cell.foregroundColor; switch (foregroundColor.type) { case 'default': sgrSeq.push('39'); break; - case 'palette16': sgrSeq.push(fgColor256to16(foregroundColor.id).toString()); break; - case 'palette256': sgrSeq.push(`38;5;${foregroundColor.id}`); break; - case 'rgb': const { red, green, blue } = foregroundColor; sgrSeq.push(`38;2;${red};${green};${blue}`); break; + case 'palette16': sgrSeq.push(fgColor256to16(foregroundColor.paletteId()).toString()); break; + case 'palette256': sgrSeq.push(`38;5;${foregroundColor.paletteId()}`); break; + case 'rgb': const [red, green, blue] = foregroundColor.rgbColor(); sgrSeq.push(`38;2;${red};${green};${blue}`); break; } } @@ -201,16 +201,16 @@ class StringSerializeHandler extends BaseSerializeHandler { const backgroundColor = cell.backgroundColor; switch (backgroundColor.type) { case 'default': sgrSeq.push('49'); break; - case 'palette16': sgrSeq.push(bgColor256to16(backgroundColor.id).toString()); break; - case 'palette256': sgrSeq.push(`48;5;${backgroundColor.id}`); break; - case 'rgb': const { red, green, blue } = backgroundColor; sgrSeq.push(`48;2;${red};${green};${blue}`); break; + case 'palette16': sgrSeq.push(bgColor256to16(backgroundColor.paletteId()).toString()); break; + case 'palette256': sgrSeq.push(`48;5;${backgroundColor.paletteId()}`); break; + case 'rgb': const [red, green, blue] = backgroundColor.rgbColor(); sgrSeq.push(`48;2;${red};${green};${blue}`); break; } } } protected _nextCell(cell: IBufferCell, oldCell: IBufferCell, row: number, col: number): void { - const foregroundColorChanged = cell.foregroundColor.hash !== oldCell.foregroundColor.hash; - const backgroundColorChanged = cell.backgroundColor.hash !== oldCell.backgroundColor.hash; + const foregroundColorChanged = !cell.foregroundColor.equals(oldCell.foregroundColor); + const backgroundColorChanged = !cell.backgroundColor.equals(oldCell.backgroundColor); const styleChanged = cell.style !== oldCell.style; if ((foregroundColorChanged || backgroundColorChanged || styleChanged) && isDefaultColorStyle(cell)) { diff --git a/src/public/Terminal.ts b/src/public/Terminal.ts index 377f7acd..61b06b51 100644 --- a/src/public/Terminal.ts +++ b/src/public/Terminal.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, Color, CellStyle} from 'xterm'; +import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, CellColor as ICellColorApi, CellStyle } from 'xterm'; import { ITerminal } from '../Types'; import { IBufferLine, ICellData } from 'common/Types'; import { IBuffer } from 'common/buffer/Types'; @@ -186,7 +186,7 @@ export class Terminal implements ITerminalApi { } class BufferApiView implements IBufferApi { - constructor(private _buffer: IBuffer) {} + constructor(private _buffer: IBuffer) { } public get cursorY(): number { return this._buffer.y; } public get cursorX(): number { return this._buffer.x; } @@ -203,7 +203,7 @@ class BufferApiView implements IBufferApi { } class BufferLineApiView implements IBufferLineApi { - constructor(private _line: IBufferLine) {} + constructor(private _line: IBufferLine) { } public get isWrapped(): boolean { return this._line.isWrapped; } public get length(): number { return this._line.length; } @@ -223,40 +223,66 @@ class BufferLineApiView implements IBufferLineApi { const COLOR_MASK = Attributes.CM_MASK | Attributes.RGB_MASK; +class CellColorApi implements ICellColorApi { + readonly type: 'default' | 'rgb' | 'palette16' | 'palette256'; + readonly value: number = 0; + + constructor(type: 'default' | 'rgb' | 'palette16' | 'palette256', value: number) { + this.type = type; + this.value = value; + } + public isDefault(): boolean { return this.value === 0; } + public equals(c: ICellColorApi): boolean { return this.value === c.value; } + public paletteId(): number { + switch (this.type) { + case 'default': + case 'palette16': + case 'palette256': return this.value & Attributes.PCOLOR_MASK; + } + return -1; + } + public rgbColor(): [number, number, number] { + if (this.type === 'rgb') { + return CellData.toColorRGB(this.value); + } + return [-1, -1, -1]; + } + + public static getDefault(): ICellColorApi { return new CellColorApi('default', 0); } +} + class BufferCellApiView implements IBufferCellApi { - constructor(private _cell: ICellData) {} + constructor(private _cell: ICellData) { } public get char(): string { return this._cell.getChars(); } public get width(): number { return this._cell.getWidth(); } - public get foregroundColor(): Color { + public get foregroundColor(): ICellColorApi { const cell = this._cell; - const hash = cell.fg & COLOR_MASK; + const value = cell.fg & COLOR_MASK; if (cell.isFgDefault()) { - return { type: 'default', hash: 0 }; + return new CellColorApi('default', 0); } else if (cell.isFgPalette()) { switch (cell.getFgColorMode()) { - case Attributes.CM_P16: return { type: 'palette16', hash, id: cell.getFgColor() }; - case Attributes.CM_P256: return { type: 'palette256', hash, id: cell.getFgColor() }; + case Attributes.CM_P16: return new CellColorApi('palette16', value); + case Attributes.CM_P256: return new CellColorApi('palette256', value); } } else if (cell.isFgRGB()) { - const [red, green, blue] = CellData.toColorRGB(cell.fg); - return { type: 'rgb', hash, red, green, blue }; + return new CellColorApi('rgb', value); } throw new Error('Invalid foregroundColor'); } - public get backgroundColor(): Color { + public get backgroundColor(): ICellColorApi { const cell = this._cell; - const hash = cell.bg & COLOR_MASK; + const value = cell.bg & COLOR_MASK; if (cell.isBgDefault()) { - return { type: 'default', hash: 0 }; + return new CellColorApi('default', 0); } else if (cell.isBgPalette()) { switch (cell.getBgColorMode()) { - case Attributes.CM_P16: return { type: 'palette16', hash, id: cell.getBgColor() }; - case Attributes.CM_P256: return { type: 'palette256', hash, id: cell.getBgColor() }; + case Attributes.CM_P16: return new CellColorApi('palette16', value); + case Attributes.CM_P256: return new CellColorApi('palette256', value); } } else if (cell.isBgRGB()) { - const [red, green, blue] = CellData.toColorRGB(cell.bg); - return { type: 'rgb', hash, red, green, blue }; + return new CellColorApi('rgb', value); } throw new Error('Invalid backgroundColor'); } diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 4503e1c1..afdfa3e4 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -952,12 +952,11 @@ declare module 'xterm' { */ readonly width: number; - readonly foregroundColor: Color; - readonly backgroundColor: Color; + readonly foregroundColor: CellColor; + readonly backgroundColor: CellColor; readonly style: CellStyle; } - export type Color = IDefaultColor | IPalette16Color | IPalette256Color | IRgbColor; export enum CellStyle { default = 0, // foreground style @@ -971,39 +970,17 @@ declare module 'xterm' { dim = 0x8000000 >>> 16 } - interface ICellColor { - type: string; - hash: number; - } + export class CellColor { + readonly type: 'default' | 'rgb' | 'palette16' | 'palette256'; + readonly value: number; - interface IDefaultColor extends ICellColor { - type: 'default'; - hash: 0; - } + constructor(type: 'default' | 'rgb' | 'palette16' | 'palette256', value: number); - interface IRgbColor extends ICellColor { - type: 'rgb'; - hash: number; + isDefault(): boolean; + equals(c: CellColor): boolean; + paletteId(): number; + rgbColor(): [number, number, number]; - // 0-255 - red: number; - green: number; - blue: number; - } - - interface IPalette16Color extends ICellColor { - type: 'palette16'; - hash: number; - - // 0-15 - id: number; - } - - interface IPalette256Color extends ICellColor { - type: 'palette256'; - hash: number; - - // 0-255 - id: number; + static getDefault(): CellColor; } }