Implement OSC 4 for list of colors

This commit is contained in:
Slawek Zachcial
2020-12-09 22:30:23 +01:00
parent 2804bfa8b7
commit 7d3f5375a8
4 changed files with 67 additions and 23 deletions
+7 -4
View File
@@ -162,11 +162,14 @@ export class Terminal extends CoreTerminal implements ITerminal {
private _changeAnsiColor(event: IAnsiColorChangeEvent): void {
if (!this._colorManager) { return; }
const color = rgba.toColor(event.red, event.green, event.blue);
event.colors.forEach(ansiColor => {
const color = rgba.toColor(ansiColor.red, ansiColor.green, ansiColor.blue);
this._colorManager.colors.ansi[event.colorIndex] = color;
this._renderService?.setColors(this._colorManager.colors);
this.viewport?.onThemeChange(this._colorManager.colors);
this._colorManager!.colors.ansi[ansiColor.colorIndex] = color;
});
this._renderService?.setColors(this._colorManager!.colors);
this.viewport?.onThemeChange(this._colorManager!.colors);
}
public dispose(): void {
+39 -9
View File
@@ -1693,16 +1693,15 @@ describe('InputHandler', () => {
});
});
describe('OSC', () => {
it('should parse correct Ansi color change data', () => {
it('4: should parse correct Ansi color change data', () => {
// this is testing a private method
const parseAnsiColorChange = inputHandler['_parseAnsiColorChange'];
const event = parseAnsiColorChange('19;rgb:a1/b2/c3');
assert.deepEqual(
parseAnsiColorChange('19;rgb:a1/b2/c3'),
{ colorIndex: 19, red: 0xa1, green: 0xb2, blue: 0xc3 }
);
assert.isNotNull(event);
assert.deepEqual(event!.colors[0], { colorIndex: 19, red: 0xa1, green: 0xb2, blue: 0xc3 });
}),
it('should ignore incorrect Ansi color change data', () => {
it('4: should ignore incorrect Ansi color change data', () => {
// this is testing a private method
const parseAnsiColorChange = inputHandler['_parseAnsiColorChange'];
@@ -1711,12 +1710,43 @@ describe('InputHandler', () => {
assert.isNull(parseAnsiColorChange('17;rgba:aa/bb/cc'));
assert.isNull(parseAnsiColorChange('rgb:aa/bb/cc'));
});
it('should fire event on Ansi color change', (done) => {
it('4: should parse a list of Ansi color changes', () => {
// this is testing a private method
const parseAnsiColorChange = inputHandler['_parseAnsiColorChange'];
const event = parseAnsiColorChange('19;rgb:a1/b2/c3;17;rgb:00/11/22;255;rgb:01/ef/2d');
assert.isNotNull(event);
assert.equal(event!.colors.length, 3);
assert.deepEqual(event!.colors[0], { colorIndex: 19, red: 0xa1, green: 0xb2, blue: 0xc3 });
assert.deepEqual(event!.colors[1], { colorIndex: 17, red: 0x00, green: 0x11, blue: 0x22 });
assert.deepEqual(event!.colors[2], { colorIndex: 255, red: 0x01, green: 0xef, blue: 0x2d });
});
it('4: should ignore incorrect colors in a list of Ansi color changes', () => {
// this is testing a private method
const parseAnsiColorChange = inputHandler['_parseAnsiColorChange'];
const event = parseAnsiColorChange('19;rgb:a1/b2/c3;17;rgb:WR/ON/G;255;rgb:01/ef/2d');
assert.equal(event!.colors.length, 2);
assert.deepEqual(event!.colors[0], { colorIndex: 19, red: 0xa1, green: 0xb2, blue: 0xc3 });
assert.deepEqual(event!.colors[1], { colorIndex: 255, red: 0x01, green: 0xef, blue: 0x2d });
});
it('4: should be case insensitive when parsing Ansi color changes', () => {
// this is testing a private method
const parseAnsiColorChange = inputHandler['_parseAnsiColorChange'];
const event = parseAnsiColorChange('19;rGb:A1/b2/C3');
assert.equal(event!.colors.length, 1);
assert.deepEqual(event!.colors[0], { colorIndex: 19, red: 0xa1, green: 0xb2, blue: 0xc3 });
});
it('4: should fire event on Ansi color change', (done) => {
inputHandler.onAnsiColorChange(e => {
assert.deepEqual(e, { colorIndex: 17, red: 0x1a, green: 0x2b, blue: 0x3c });
assert.isNotNull(e);
assert.isNotNull(e!.colors);
assert.deepEqual(e!.colors[0], { colorIndex: 17, red: 0x1a, green: 0x2b, blue: 0x3c });
assert.deepEqual(e!.colors[1], { colorIndex: 12, red: 0x11, green: 0x22, blue: 0x33 });
done();
});
inputHandler.parse('\x1b]4;17;rgb:1a/2b/3c\x1b\\');
inputHandler.parse('\x1b]4;17;rgb:1a/2b/3c;12;rgb:11/22/33\x1b\\');
});
});
});
+13 -6
View File
@@ -2715,19 +2715,25 @@ export class InputHandler extends Disposable implements IInputHandler {
}
private _parseAnsiColorChange(data: string): IAnsiColorChangeEvent | null {
const result: IAnsiColorChangeEvent = { colors: [] };
// 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);
const regex = /(\d+);rgb:([0-9a-f]{2})\/([0-9a-f]{2})\/([0-9a-f]{2})/gi;
let match;
if (match) {
return {
while ((match = regex.exec(data)) !== null) {
result.colors.push({
colorIndex: parseInt(match[1]),
red: parseInt(match[2], 16),
green: parseInt(match[3], 16),
blue: parseInt(match[4], 16)
};
});
}
return null;
if (result.colors.length === 0) {
return null;
}
return result;
}
/**
@@ -2735,6 +2741,7 @@ export class InputHandler extends Disposable implements IInputHandler {
*
* @vt: #Y OSC 4 "Set ANSI color" "OSC 4 ; c ; spec BEL" "Change color number `c` to the color specified by `spec`."
* `c` is the color index between 0 and 255. `spec` color format is 'rgb:hh/hh/hh' where `h` are hexadecimal digits.
* There may be multipe c ; spec elements present in the same instruction, e.g. 1;rgb:10/20/30;2;rgb:a0/b0/c0.
*/
public setAnsiColor(data: string): void {
const event = this._parseAnsiColorChange(data);
+8 -4
View File
@@ -328,16 +328,20 @@ export interface IWindowOptions {
setWinLines?: boolean;
}
/**
* Event fired for OSC 4 command - to change ANSI color based on its index.
*/
export interface IAnsiColorChangeEvent {
export interface IAnsiColorChangeEventColor {
colorIndex: number;
red: number;
green: number;
blue: number;
}
/**
* Event fired for OSC 4 command - to change ANSI color based on its index.
*/
export interface IAnsiColorChangeEvent {
colors: IAnsiColorChangeEventColor[];
}
/**
* Calls the parser and handles actions generated by the parser.
*/