diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 216b541a..9452833e 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -39,7 +39,7 @@ import { MouseZoneManager } from 'browser/MouseZoneManager'; import { AccessibilityManager } from './AccessibilityManager'; import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider } from 'xterm'; import { DomRenderer } from 'browser/renderer/dom/DomRenderer'; -import { IKeyboardEvent, KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, IColorRGB } from 'common/Types'; +import { IKeyboardEvent, KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, IAnsiColorChangeEvent } from 'common/Types'; import { evaluateKeyboardEvent } from 'common/input/Keyboard'; import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter'; import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; @@ -149,9 +149,9 @@ export class Terminal extends CoreTerminal implements ITerminal { this.register(this._inputHandler.onRequestReset(() => this.reset())); this.register(this._inputHandler.onRequestScroll((eraseAttr, isWrapped) => this.scroll(eraseAttr, isWrapped || undefined))); this.register(this._inputHandler.onRequestWindowsOptionsReport(type => this._reportWindowsOptions(type))); + this.register(this._inputHandler.onAnsiColorChange((event) => this._changeAnsiColor(event))); this.register(forwardEvent(this._inputHandler.onCursorMove, this._onCursorMove)); this.register(forwardEvent(this._inputHandler.onTitleChange, this._onTitleChange)); - this.register(this._inputHandler.onAnsiColorChange((index, color) => this._changeAnsiColor(index, color))); this.register(forwardEvent(this._inputHandler.onA11yChar, this._onA11yCharEmitter)); this.register(forwardEvent(this._inputHandler.onA11yTab, this._onA11yTabEmitter)); @@ -159,10 +159,10 @@ export class Terminal extends CoreTerminal implements ITerminal { this.register(this._bufferService.onResize(e => this._afterResize(e.cols, e.rows))); } - private _changeAnsiColor(colorIndex: number, colorRGB: IColorRGB): void { - const color = rgba.toColor(colorRGB[0], colorRGB[1], colorRGB[2]); + private _changeAnsiColor(event: IAnsiColorChangeEvent): void { + const color = rgba.toColor(event.red, event.green, event.blue); - this._colorManager!.colors.ansi[colorIndex] = color; + this._colorManager!.colors.ansi[event.colorIndex] = color; this._renderService?.setColors(this._colorManager!.colors); this.viewport?.onThemeChange(this._colorManager!.colors); } diff --git a/src/common/InputHandler.test.ts b/src/common/InputHandler.test.ts index 46f8eacc..6ff0fd57 100644 --- a/src/common/InputHandler.test.ts +++ b/src/common/InputHandler.test.ts @@ -5,7 +5,7 @@ import { assert, expect } from 'chai'; import { InputHandler } from 'common/InputHandler'; -import { IBufferLine, IAttributeData } from 'common/Types'; +import { IBufferLine, IAttributeData, IAnsiColorChangeEvent } from 'common/Types'; import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { CellData } from 'common/buffer/CellData'; import { Attributes, UnderlineStyle } from 'common/buffer/Constants'; diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 1b235abf..0bd1b3a6 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -4,7 +4,7 @@ * @license MIT */ -import { IInputHandler, IAttributeData, IDisposable, IWindowOptions, IColorRGB } from 'common/Types'; +import { IInputHandler, IAttributeData, IDisposable, IWindowOptions, IAnsiColorChangeEvent } from 'common/Types'; import { C0, C1 } from 'common/data/EscapeSequences'; import { CHARSETS, DEFAULT_CHARSET } from 'common/data/Charsets'; import { EscapeSequenceParser } from 'common/parser/EscapeSequenceParser'; @@ -250,8 +250,8 @@ export class InputHandler extends Disposable implements IInputHandler { public get onScroll(): IEvent { return this._onScroll.event; } private _onTitleChange = new EventEmitter(); public get onTitleChange(): IEvent { return this._onTitleChange.event; } - private _onAnsiColorChange = new EventEmitter(); - public get onAnsiColorChange(): IEvent { return this._onAnsiColorChange.event; } + private _onAnsiColorChange = new EventEmitter(); + public get onAnsiColorChange(): IEvent { return this._onAnsiColorChange.event; } constructor( private readonly _bufferService: IBufferService, @@ -2714,27 +2714,33 @@ export class InputHandler extends Disposable implements IInputHandler { this._iconName = data; } + // This is really an internal method and not part of IInputHandler implementation. + // Making it public so that I can test it. + public parseAnsiColorChange(data: string): IAnsiColorChangeEvent | null { + // example data: 5;rgb:aa/bb/cc + const regex = /(\d+);rgb:([0-9a-fA-F]{2})\/([0-9a-fA-F]{2})\/([0-9a-fA-F]{2})/; + const match = data.match(regex); + + if (match) { + return { + colorIndex: parseInt(match[1]), + red: parseInt(match[2], 16), + green: parseInt(match[3], 16), + blue: parseInt(match[4], 16) + }; + } + return null; + } + /** * OSC 4; ; ST (set ANSI color to ) * * The expected content of data is: ;rgb:// where rr, gg, bb are hex numbers. */ public setAnsiColor(data: string): void { - // example data: 5;rgb:aa/bb/cc - const regex = /(\d+);rgb:([0-9a-fA-F]{2})\/([0-9a-fA-F]{2})\/([0-9a-fA-F]{2})/; - const match = data.match(regex); - - if (match) { - const colorIndex = parseInt(match[1]); - const color: IColorRGB = [ - parseInt(match[2], 16), - parseInt(match[3], 16), - parseInt(match[4], 16) - ]; - - // TODO: remove debug - console.log(`Setting ANSI color ${colorIndex} to RGB value ${color}`); - this._onAnsiColorChange.fire(colorIndex, color); + const event = this.parseAnsiColorChange(data); + if (event) { + this._onAnsiColorChange.fire(event); } else { this._logService.warn(`Expected format ;rgb:// but got data: ${data}`); diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index 4967da12..cbb11b3f 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -328,6 +328,16 @@ export interface IWindowOptions { setWinLines?: boolean; } +/** + * Event fired for OSC 4 command - to change ANSI color based on its index. + */ +export interface IAnsiColorChangeEvent { + colorIndex: number; + red: number; + green: number; + blue: number; +} + /** * Calls the parser and handles actions generated by the parser. */