mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
underline color support, test cases
This commit is contained in:
+104
-1
@@ -1445,7 +1445,7 @@ describe('InputHandler', () => {
|
||||
assert.deepEqual(getLines(term), ['¥¥ ¥¥', '¥¥ ¥', '¥¥ ¥', '¥¥¥¥¥', '']);
|
||||
});
|
||||
});
|
||||
describe('extended SGR 4 support', () => {
|
||||
describe('extended underline style support (SGR 4)', () => {
|
||||
let term: TestTerminal;
|
||||
beforeEach(() => {
|
||||
term = new TestTerminal({cols: 10, rows: 5});
|
||||
@@ -1519,4 +1519,107 @@ describe('InputHandler', () => {
|
||||
assert.equal(term.curAttrData.getUnderlineStyle(), UnderlineStyle.SINGLE);
|
||||
});
|
||||
});
|
||||
describe('underline colors (SGR 58 & SGR 59)', () => {
|
||||
let term: TestTerminal;
|
||||
beforeEach(() => {
|
||||
term = new TestTerminal({cols: 10, rows: 5});
|
||||
});
|
||||
it('defaults to FG color', () => {
|
||||
for (const s of ['', '\x1b[30m', '\x1b[38;510m', '\x1b[38;2;1;2;3m']) {
|
||||
term.writeSync(s);
|
||||
assert.equal(term.curAttrData.getUnderlineColor(), term.curAttrData.getFgColor());
|
||||
assert.equal(term.curAttrData.getUnderlineColorMode(), term.curAttrData.getFgColorMode());
|
||||
assert.equal(term.curAttrData.isUnderlineColorRGB(), term.curAttrData.isFgRGB());
|
||||
assert.equal(term.curAttrData.isUnderlineColorPalette(), term.curAttrData.isFgPalette());
|
||||
assert.equal(term.curAttrData.isUnderlineColorDefault(), term.curAttrData.isFgDefault());
|
||||
}
|
||||
});
|
||||
it('correctly sets P256/RGB colors', () => {
|
||||
term.writeSync('\x1b[4m');
|
||||
term.writeSync('\x1b[58;5;123m');
|
||||
assert.equal(term.curAttrData.getUnderlineColor(), 123);
|
||||
assert.equal(term.curAttrData.getUnderlineColorMode(), Attributes.CM_P256);
|
||||
assert.equal(term.curAttrData.isUnderlineColorRGB(), false);
|
||||
assert.equal(term.curAttrData.isUnderlineColorPalette(), true);
|
||||
assert.equal(term.curAttrData.isUnderlineColorDefault(), false);
|
||||
term.writeSync('\x1b[58;2::1:2:3m');
|
||||
assert.equal(term.curAttrData.getUnderlineColor(), (1 << 16) | (2 << 8) | 3);
|
||||
assert.equal(term.curAttrData.getUnderlineColorMode(), Attributes.CM_RGB);
|
||||
assert.equal(term.curAttrData.isUnderlineColorRGB(), true);
|
||||
assert.equal(term.curAttrData.isUnderlineColorPalette(), false);
|
||||
assert.equal(term.curAttrData.isUnderlineColorDefault(), false);
|
||||
});
|
||||
it('P256/RGB persistence', () => {
|
||||
const cell = new CellData();
|
||||
term.writeSync('\x1b[4m');
|
||||
term.writeSync('\x1b[58;5;123m');
|
||||
assert.equal(term.curAttrData.getUnderlineColor(), 123);
|
||||
assert.equal(term.curAttrData.getUnderlineColorMode(), Attributes.CM_P256);
|
||||
assert.equal(term.curAttrData.isUnderlineColorRGB(), false);
|
||||
assert.equal(term.curAttrData.isUnderlineColorPalette(), true);
|
||||
assert.equal(term.curAttrData.isUnderlineColorDefault(), false);
|
||||
term.writeSync('ab');
|
||||
(term as any)._bufferService.buffers.active.lines.get(0).loadCell(1, cell);
|
||||
assert.equal(cell.getUnderlineColor(), 123);
|
||||
assert.equal(cell.getUnderlineColorMode(), Attributes.CM_P256);
|
||||
assert.equal(cell.isUnderlineColorRGB(), false);
|
||||
assert.equal(cell.isUnderlineColorPalette(), true);
|
||||
assert.equal(cell.isUnderlineColorDefault(), false);
|
||||
|
||||
term.writeSync('\x1b[4:0m');
|
||||
assert.equal(term.curAttrData.getUnderlineColor(), term.curAttrData.getFgColor());
|
||||
assert.equal(term.curAttrData.getUnderlineColorMode(), term.curAttrData.getFgColorMode());
|
||||
assert.equal(term.curAttrData.isUnderlineColorRGB(), term.curAttrData.isFgRGB());
|
||||
assert.equal(term.curAttrData.isUnderlineColorPalette(), term.curAttrData.isFgPalette());
|
||||
assert.equal(term.curAttrData.isUnderlineColorDefault(), term.curAttrData.isFgDefault());
|
||||
term.writeSync('a');
|
||||
(term as any)._bufferService.buffers.active.lines.get(0).loadCell(1, cell);
|
||||
assert.equal(cell.getUnderlineColor(), 123);
|
||||
assert.equal(cell.getUnderlineColorMode(), Attributes.CM_P256);
|
||||
assert.equal(cell.isUnderlineColorRGB(), false);
|
||||
assert.equal(cell.isUnderlineColorPalette(), true);
|
||||
assert.equal(cell.isUnderlineColorDefault(), false);
|
||||
(term as any)._bufferService.buffers.active.lines.get(0).loadCell(2, cell);
|
||||
assert.equal(cell.getUnderlineColor(), term.curAttrData.getFgColor());
|
||||
assert.equal(cell.getUnderlineColorMode(), term.curAttrData.getFgColorMode());
|
||||
assert.equal(cell.isUnderlineColorRGB(), term.curAttrData.isFgRGB());
|
||||
assert.equal(cell.isUnderlineColorPalette(), term.curAttrData.isFgPalette());
|
||||
assert.equal(cell.isUnderlineColorDefault(), term.curAttrData.isFgDefault());
|
||||
|
||||
term.writeSync('\x1b[4m');
|
||||
term.writeSync('\x1b[58;2::1:2:3m');
|
||||
assert.equal(term.curAttrData.getUnderlineColor(), (1 << 16) | (2 << 8) | 3);
|
||||
assert.equal(term.curAttrData.getUnderlineColorMode(), Attributes.CM_RGB);
|
||||
assert.equal(term.curAttrData.isUnderlineColorRGB(), true);
|
||||
assert.equal(term.curAttrData.isUnderlineColorPalette(), false);
|
||||
assert.equal(term.curAttrData.isUnderlineColorDefault(), false);
|
||||
term.writeSync('a');
|
||||
term.writeSync('\x1b[24m');
|
||||
(term as any)._bufferService.buffers.active.lines.get(0).loadCell(1, cell);
|
||||
assert.equal(cell.getUnderlineColor(), 123);
|
||||
assert.equal(cell.getUnderlineColorMode(), Attributes.CM_P256);
|
||||
assert.equal(cell.isUnderlineColorRGB(), false);
|
||||
assert.equal(cell.isUnderlineColorPalette(), true);
|
||||
assert.equal(cell.isUnderlineColorDefault(), false);
|
||||
(term as any)._bufferService.buffers.active.lines.get(0).loadCell(3, cell);
|
||||
assert.equal(cell.getUnderlineColor(), (1 << 16) | (2 << 8) | 3);
|
||||
assert.equal(cell.getUnderlineColorMode(), Attributes.CM_RGB);
|
||||
assert.equal(cell.isUnderlineColorRGB(), true);
|
||||
assert.equal(cell.isUnderlineColorPalette(), false);
|
||||
assert.equal(cell.isUnderlineColorDefault(), false);
|
||||
|
||||
// eAttrs in buffer pos 0 and 1 should be the same object
|
||||
assert.equal(
|
||||
(term as any)._bufferService.buffers.active.lines.get(0)._extendedAttrs[0],
|
||||
(term as any)._bufferService.buffers.active.lines.get(0)._extendedAttrs[1]
|
||||
);
|
||||
// should not have written eAttr for pos 2 in the buffer
|
||||
assert.equal((term as any)._bufferService.buffers.active.lines.get(0)._extendedAttrs[2], undefined);
|
||||
// eAttrs in buffer pos 1 and pos 3 must be different objs
|
||||
assert.notEqual(
|
||||
(term as any)._bufferService.buffers.active.lines.get(0)._extendedAttrs[1],
|
||||
(term as any)._bufferService.buffers.active.lines.get(0)._extendedAttrs[3]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+31
-24
@@ -2026,6 +2026,21 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to write color information packed with color mode.
|
||||
*/
|
||||
private _updateColor(color: number, mode: number, c1: number, c2: number, c3: number): number {
|
||||
if (mode === 2) {
|
||||
color |= Attributes.CM_RGB;
|
||||
color &= ~Attributes.RGB_MASK;
|
||||
color |= AttributeData.fromColorRGB([c1, c2, c3]);
|
||||
} else if (mode === 5) {
|
||||
color &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
|
||||
color |= Attributes.CM_P256 | (c1 & 0xff);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to extract and apply color params/subparams.
|
||||
* Returns advance for params index.
|
||||
@@ -2075,24 +2090,16 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
}
|
||||
|
||||
// apply colors
|
||||
if (accu[0] === 38) {
|
||||
if (accu[1] === 2) {
|
||||
attr.fg |= Attributes.CM_RGB;
|
||||
attr.fg &= ~Attributes.RGB_MASK;
|
||||
attr.fg |= AttributeData.fromColorRGB([accu[3], accu[4], accu[5]]);
|
||||
} else if (accu[1] === 5) {
|
||||
attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
|
||||
attr.fg |= Attributes.CM_P256 | (accu[3] & 0xff);
|
||||
}
|
||||
} else if (accu[0] === 48) {
|
||||
if (accu[1] === 2) {
|
||||
attr.bg |= Attributes.CM_RGB;
|
||||
attr.bg &= ~Attributes.RGB_MASK;
|
||||
attr.bg |= AttributeData.fromColorRGB([accu[3], accu[4], accu[5]]);
|
||||
} else if (accu[1] === 5) {
|
||||
attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
|
||||
attr.bg |= Attributes.CM_P256 | (accu[3] & 0xff);
|
||||
}
|
||||
switch (accu[0]) {
|
||||
case 38:
|
||||
attr.fg = this._updateColor(attr.fg, accu[1], accu[3], accu[4], accu[5]);
|
||||
break;
|
||||
case 48:
|
||||
attr.bg = this._updateColor(attr.bg, accu[1], accu[3], accu[4], accu[5]);
|
||||
break;
|
||||
case 58:
|
||||
attr.extended = attr.extended.clone();
|
||||
attr.extended.underlineColor = this._updateColor(attr.extended.underlineColor, accu[1], accu[3], accu[4], accu[5]);
|
||||
}
|
||||
|
||||
return advance;
|
||||
@@ -2125,11 +2132,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
}
|
||||
|
||||
// update HAS_EXTENDED in BG
|
||||
if (attr.extended.isEmpty()) {
|
||||
attr.bg &= ~BgFlags.HAS_EXTENDED;
|
||||
} else {
|
||||
attr.bg |= BgFlags.HAS_EXTENDED;
|
||||
}
|
||||
attr.updateExtended();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2300,9 +2303,13 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
// reset bg
|
||||
attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
|
||||
attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
|
||||
} else if (p === 38 || p === 48) {
|
||||
} else if (p === 38 || p === 48 || p === 58) {
|
||||
// fg color 256 and RGB
|
||||
i += this._extractColor(params, i, attr);
|
||||
} else if (p === 59) {
|
||||
attr.extended = attr.extended.clone();
|
||||
attr.extended.underlineColor = -1;
|
||||
attr.updateExtended();
|
||||
} else if (p === 100) { // FIXME: dead branch, p=100 already handled above!
|
||||
// reset fg/bg
|
||||
attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
|
||||
|
||||
Vendored
+5
@@ -109,7 +109,12 @@ export interface IAttributeData {
|
||||
|
||||
// extended attrs
|
||||
hasExtendedAttrs(): number;
|
||||
updateExtended(): void;
|
||||
getUnderlineColor(): number;
|
||||
getUnderlineColorMode(): number;
|
||||
isUnderlineColorRGB(): boolean;
|
||||
isUnderlineColorPalette(): boolean;
|
||||
isUnderlineColorDefault(): boolean;
|
||||
getUnderlineStyle(): number;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,12 +73,45 @@ export class AttributeData implements IAttributeData {
|
||||
public hasExtendedAttrs(): number {
|
||||
return this.bg & BgFlags.HAS_EXTENDED;
|
||||
}
|
||||
public updateExtended(): void {
|
||||
if (this.extended.isEmpty()) {
|
||||
this.bg &= ~BgFlags.HAS_EXTENDED;
|
||||
} else {
|
||||
this.bg |= BgFlags.HAS_EXTENDED;
|
||||
}
|
||||
}
|
||||
public getUnderlineColor(): number {
|
||||
if ((this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor) {
|
||||
return this.extended.underlineColor;
|
||||
switch (this.extended.underlineColor & Attributes.CM_MASK) {
|
||||
case Attributes.CM_P16:
|
||||
case Attributes.CM_P256: return this.extended.underlineColor & Attributes.PCOLOR_MASK;
|
||||
case Attributes.CM_RGB: return this.extended.underlineColor & Attributes.RGB_MASK;
|
||||
default: return this.getFgColor();
|
||||
}
|
||||
}
|
||||
return this.getFgColor();
|
||||
}
|
||||
public getUnderlineColorMode(): number {
|
||||
return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor
|
||||
? this.extended.underlineColor & Attributes.CM_MASK
|
||||
: this.getFgColorMode();
|
||||
}
|
||||
public isUnderlineColorRGB(): boolean {
|
||||
return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor
|
||||
? (this.extended.underlineColor & Attributes.CM_MASK) === Attributes.CM_RGB
|
||||
: this.isFgRGB();
|
||||
}
|
||||
public isUnderlineColorPalette(): boolean {
|
||||
return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor
|
||||
? (this.extended.underlineColor & Attributes.CM_MASK) === Attributes.CM_P16
|
||||
|| (this.extended.underlineColor & Attributes.CM_MASK) === Attributes.CM_P256
|
||||
: this.isFgPalette();
|
||||
}
|
||||
public isUnderlineColorDefault(): boolean {
|
||||
return (this.bg & BgFlags.HAS_EXTENDED) && ~this.extended.underlineColor
|
||||
? (this.extended.underlineColor & Attributes.CM_MASK) === 0
|
||||
: this.isFgDefault();
|
||||
}
|
||||
public getUnderlineStyle(): UnderlineStyle {
|
||||
return this.fg & FgFlags.UNDERLINE
|
||||
? (this.bg & BgFlags.HAS_EXTENDED ? this.extended.underlineStyle : UnderlineStyle.SINGLE)
|
||||
@@ -104,11 +137,10 @@ export class ExtendedAttrs implements IExtendedAttrs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient method to indicate whether the object holds no additional information
|
||||
* and can be removed from the global attr object.
|
||||
* Convenient method to indicate whether the object holds no additional information,
|
||||
* that needs to be persistant in the buffer.
|
||||
*/
|
||||
public isEmpty(): boolean {
|
||||
// needs to test for every single attribute stored
|
||||
return !(this.underlineStyle !== UnderlineStyle.NONE || ~this.underlineColor);
|
||||
return this.underlineStyle === UnderlineStyle.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,27 @@ describe('AttributeData', () => {
|
||||
attrs.bg |= BgFlags.HAS_EXTENDED;
|
||||
assert.equal(!!attrs.hasExtendedAttrs(), true);
|
||||
});
|
||||
it('getUnderlineColor', () => {
|
||||
it('getUnderlineColor - P256', () => {
|
||||
const attrs = new AttributeData();
|
||||
attrs.extended.underlineColor = (1 << 16) | (2 << 8) | 3;
|
||||
// set a P256 color
|
||||
attrs.extended.underlineColor = Attributes.CM_P256 | 45;
|
||||
|
||||
// should use FG color if BgFlags.HAS_EXTENDED is not set
|
||||
assert.equal(attrs.getUnderlineColor(), -1);
|
||||
|
||||
// should use underlineColor if BgFlags.HAS_EXTENDED is set and underlineColor holds a value
|
||||
attrs.bg |= BgFlags.HAS_EXTENDED;
|
||||
assert.equal(attrs.getUnderlineColor(), 45);
|
||||
|
||||
// should use FG color if underlineColor holds no value
|
||||
attrs.extended.underlineColor = -1;
|
||||
attrs.fg |= Attributes.CM_P256 | 123;
|
||||
assert.equal(attrs.getUnderlineColor(), 123);
|
||||
});
|
||||
it('getUnderlineColor - RGB', () => {
|
||||
const attrs = new AttributeData();
|
||||
// set a P256 color
|
||||
attrs.extended.underlineColor = Attributes.CM_RGB | (1 << 16) | (2 << 8) | 3;
|
||||
|
||||
// should use FG color if BgFlags.HAS_EXTENDED is not set
|
||||
assert.equal(attrs.getUnderlineColor(), -1);
|
||||
@@ -48,6 +66,37 @@ describe('AttributeData', () => {
|
||||
attrs.fg |= Attributes.CM_P256 | 123;
|
||||
assert.equal(attrs.getUnderlineColor(), 123);
|
||||
});
|
||||
it('getUnderlineColorMode / isUnderlineColorRGB / isUnderlineColorPalette / isUnderlineColorDefault', () => {
|
||||
const attrs = new AttributeData();
|
||||
|
||||
// should always return color mode of fg
|
||||
for (const mode of [Attributes.CM_DEFAULT, Attributes.CM_P16, Attributes.CM_P256, Attributes.CM_RGB]) {
|
||||
attrs.extended.underlineColor = mode;
|
||||
assert.equal(attrs.getUnderlineColorMode(), attrs.getFgColorMode());
|
||||
assert.equal(attrs.isUnderlineColorDefault(), true);
|
||||
}
|
||||
attrs.fg = Attributes.CM_RGB;
|
||||
for (const mode of [Attributes.CM_DEFAULT, Attributes.CM_P16, Attributes.CM_P256, Attributes.CM_RGB]) {
|
||||
attrs.extended.underlineColor = mode;
|
||||
assert.equal(attrs.getUnderlineColorMode(), attrs.getFgColorMode());
|
||||
assert.equal(attrs.isUnderlineColorDefault(), false);
|
||||
assert.equal(attrs.isUnderlineColorRGB(), true);
|
||||
}
|
||||
|
||||
// should return own mode
|
||||
attrs.bg |= BgFlags.HAS_EXTENDED;
|
||||
attrs.extended.underlineColor = Attributes.CM_DEFAULT;
|
||||
assert.equal(attrs.getUnderlineColorMode(), Attributes.CM_DEFAULT);
|
||||
attrs.extended.underlineColor = Attributes.CM_P16;
|
||||
assert.equal(attrs.getUnderlineColorMode(), Attributes.CM_P16);
|
||||
assert.equal(attrs.isUnderlineColorPalette(), true);
|
||||
attrs.extended.underlineColor = Attributes.CM_P256;
|
||||
assert.equal(attrs.getUnderlineColorMode(), Attributes.CM_P256);
|
||||
assert.equal(attrs.isUnderlineColorPalette(), true);
|
||||
attrs.extended.underlineColor = Attributes.CM_RGB;
|
||||
assert.equal(attrs.getUnderlineColorMode(), Attributes.CM_RGB);
|
||||
assert.equal(attrs.isUnderlineColorRGB(), true);
|
||||
});
|
||||
it('getUnderlineStyle', () => {
|
||||
const attrs = new AttributeData();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user