From 4d70606febacd6bd1e9b2b8ec0d4cfc216661f9d Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Thu, 3 Feb 2022 18:00:16 +0000 Subject: [PATCH] Apply feedback from code review --- .../src/SerializeAddon.ts | 56 +++++++++---------- .../typings/xterm-addon-serialize.d.ts | 33 ++++++++++- demo/client.ts | 5 +- 3 files changed, 59 insertions(+), 35 deletions(-) diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index b7cb00a9..20377cec 100644 --- a/addons/xterm-addon-serialize/src/SerializeAddon.ts +++ b/addons/xterm-addon-serialize/src/SerializeAddon.ts @@ -416,9 +416,9 @@ export class SerializeAddon implements ITerminalAddon { }); } - private _htmlserializeBuffer(terminal: Terminal, options: Partial): string { + private _serializeBufferAsHTML(terminal: Terminal, options: Partial): string { const buffer = terminal.buffer.active; - const handler = new HTMLSerializeHandler(buffer, terminal); + const handler = new HTMLSerializeHandler(buffer, terminal, options); const onlySelection = options.onlySelection ?? true; if (!onlySelection) { const maxRows = buffer.length; @@ -495,12 +495,12 @@ export class SerializeAddon implements ITerminalAddon { return content; } - public htmlserialize(options?: Partial): string { + public serializeAsHTML(options?: Partial): string { if (!this._terminal) { throw new Error('Cannot use addon until it has been loaded'); } - return this._htmlserializeBuffer(this._terminal, options || {}); + return this._serializeBufferAsHTML(this._terminal, options || {}); } public dispose(): void { } @@ -513,9 +513,10 @@ interface ISerializeOptions { excludeAltBuffer?: boolean; } -interface IHtmlSerializeOptions { +interface IHTMLSerializeOptions { scrollback: number; onlySelection: boolean; + includeGlobalBackground: boolean; } export class HTMLSerializeHandler extends BaseSerializeHandler { @@ -523,20 +524,12 @@ export class HTMLSerializeHandler extends BaseSerializeHandler { private _htmlContent = ''; - private _inverseStyle = 'color: #000000; background-color: #BFBFBF;'; - private _blinkStyle = 'text-decoration: blink;'; - private _boldStyle = 'font-weight: bold;'; - private _italicStyle = 'font-style: italic;'; - private _underlineStyle = 'text-decoration: underline;'; - private _strikethroughStyle = 'text-decoration: line-through;'; - private _invisibleStyle = 'visibility: hidden;'; - private _dimStyle = 'opacity: 0.5;'; - private _colors: IColorSet; constructor( buffer: IBuffer, - private readonly _terminal: Terminal + private readonly _terminal: Terminal, + private readonly _options: Partial ) { super(buffer); @@ -559,11 +552,14 @@ export class HTMLSerializeHandler extends BaseSerializeHandler { } protected _beforeSerialize(rows: number, start: number, end: number): void { - this._htmlContent += '' - + '
';
+    this._htmlContent += '
';
 
-    const foreground = this._terminal.options.theme?.foreground ?? '#ffffff';
-    const background = this._terminal.options.theme?.background ?? '#000000';
+    let foreground = '#000000';
+    let background = '#ffffff';
+    if (this._options.includeGlobalBackground ?? true) {
+      foreground = this._terminal.options.theme?.foreground ?? '#ffffff';
+      background = this._terminal.options.theme?.background ?? '#000000';
+    }
 
     const globalStyleDefinitions = [];
     globalStyleDefinitions.push('color: ' + foreground + ';');
@@ -579,7 +575,7 @@ export class HTMLSerializeHandler extends BaseSerializeHandler {
   }
 
   protected _rowEnd(row: number, isLastRow: boolean): void {
-    this._htmlContent += '' + this._currentRow + '
'; + this._htmlContent += '
' + this._currentRow + '
'; this._currentRow = ''; } @@ -617,14 +613,14 @@ export class HTMLSerializeHandler extends BaseSerializeHandler { content.push('background-color: ' + bgHexColor + ';'); } - if (cell.isInverse()) { content.push(this._inverseStyle); } - if (cell.isBold()) { content.push(this._boldStyle); } - if (cell.isUnderline()) { content.push(this._underlineStyle); } - if (cell.isBlink()) { content.push(this._blinkStyle); } - if (cell.isInvisible()) { content.push(this._invisibleStyle); } - if (cell.isItalic()) { content.push(this._italicStyle); } - if (cell.isDim()) { content.push(this._dimStyle); } - if (cell.isStrikethrough()) { content.push(this._strikethroughStyle); } + if (cell.isInverse()) { content.push('color: #000000; background-color: #BFBFBF;'); } + if (cell.isBold()) { content.push('font-weight: bold;'); } + if (cell.isUnderline()) { content.push('text-decoration: underline;'); } + if (cell.isBlink()) { content.push('text-decoration: blink;'); } + if (cell.isInvisible()) { content.push('visibility: hidden;'); } + if (cell.isItalic()) { content.push('font-style: italic;'); } + if (cell.isDim()) { content.push('opacity: 0.5;'); } + if (cell.isStrikethrough()) { content.push('text-decoration: line-through;'); } return content; } @@ -647,8 +643,8 @@ export class HTMLSerializeHandler extends BaseSerializeHandler { // handles style change if (styleDefinitions) { this._currentRow += styleDefinitions.length === 0 ? - `` : - ``; + '' : + ''; } // handles actual content diff --git a/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts b/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts index f50fc4de..63e2c206 100644 --- a/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts +++ b/addons/xterm-addon-serialize/typings/xterm-addon-serialize.d.ts @@ -24,14 +24,23 @@ declare module 'xterm-addon-serialize' { * the state. The cursor will also be positioned to the correct cell. When restoring a terminal * it is best to do before `Terminal.open` is called to avoid wasting CPU cycles rendering * incomplete frames. - * + * * It's recommended that you write the serialized data into a terminal of the same size in which * it originated from and then resize it after if needed. - * + * * @param options Custom options to allow control over what gets serialized. */ public serialize(options?: ISerializeOptions): string; + /** + * Serializes terminal rows into a HTML string. The output of this function can be written + * to the OS clipboard. If an application supports pasting HTML, the content of the terminal + * is pasted with style options retained. + * + * @param options Custom options to allow control over what gets serialized. + */ + public serializeAsHTML(options?: Partial): string; + /** * Disposes the addon. */ @@ -56,4 +65,24 @@ declare module 'xterm-addon-serialize' { */ excludeAltBuffer?: boolean; } + + export interface IHTMLSerializeOptions { + /** + * The number of rows in the scrollback buffer to serialize, starting from the bottom of the + * scrollback buffer. When not specified, all available rows in the scrollback buffer will be + * serialized. + */ + scrollback: number; + + /** + * Whether to only serialize the selection. If false, the whole active buffer is serialized in HTML. + * True by default. + */ + onlySelection: boolean; + + /** + * Whether to include the global background of the terminal. True by default. + */ + includeGlobalBackground: boolean; + } } diff --git a/demo/client.ts b/demo/client.ts index e6b2d385..1b3987bd 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -449,12 +449,11 @@ function serializeButtonHandler(): void { } function htmlSerializeButtonHandler(): void { - const output = addons.serialize.instance.htmlserialize(); + const output = addons.serialize.instance.serializeAsHTML(); document.getElementById('htmlserialize-output').innerText = output; // Deprecated, but the most supported for now. - function listener(e) { - e.clipboardData.setData("text/html", output); + function listener(e: any) { e.clipboardData.setData("text/plain", output); e.preventDefault(); }