RGB support in buffer and attributes

This commit is contained in:
Jörg Breitbart
2019-01-13 23:19:56 +01:00
parent 7c6dad5805
commit c444eebd89
14 changed files with 589 additions and 247 deletions
+77 -76
View File
@@ -4,19 +4,17 @@
* @license MIT
*/
import { IInputHandler, IDcsHandler, IEscapeSequenceParser, IBuffer, IInputHandlingTerminal } from './Types';
import { IInputHandler, IDcsHandler, IEscapeSequenceParser, IInputHandlingTerminal } from './Types';
import { C0, C1 } from './common/data/EscapeSequences';
import { CHARSETS, DEFAULT_CHARSET } from './core/data/Charsets';
import { DEFAULT_ATTR, NULL_CELL_WIDTH, NULL_CELL_CODE } from './Buffer';
import { FLAGS } from './renderer/Types';
import { NULL_CELL_WIDTH, NULL_CELL_CODE, DEFAULT_ATTR_DATA } from './Buffer';
import { wcwidth } from './CharWidth';
import { EscapeSequenceParser } from './EscapeSequenceParser';
import { ICharset } from './core/Types';
import { IDisposable } from 'xterm';
import { Disposable } from './common/Lifecycle';
import { concat, utf32ToString } from './common/TypedArrayUtils';
import { StringToUtf32, stringFromCodePoint } from './core/input/TextDecoder';
import { CellData } from './BufferLine';
import { CellData, Attributes, FgFlags, BgFlags } from './BufferLine';
/**
* Map collect to glevel. Used in `selectCharset`.
@@ -314,13 +312,13 @@ export class InputHandler extends Disposable implements IInputHandler {
public print(data: Uint32Array, start: number, end: number): void {
let code: number;
let chWidth: number;
const buffer: IBuffer = this._terminal.buffer;
const charset: ICharset = this._terminal.charset;
const screenReaderMode: boolean = this._terminal.options.screenReaderMode;
const cols: number = this._terminal.cols;
const wraparoundMode: boolean = this._terminal.wraparoundMode;
const insertMode: boolean = this._terminal.insertMode;
const curAttr: number = this._terminal.curAttr;
const buffer = this._terminal.buffer;
const charset = this._terminal.charset;
const screenReaderMode = this._terminal.options.screenReaderMode;
const cols = this._terminal.cols;
const wraparoundMode = this._terminal.wraparoundMode;
const insertMode = this._terminal.insertMode;
const curAttr = this._terminal.curAttrData;
let bufferRow = buffer.lines.get(buffer.y + buffer.ybase);
this._terminal.updateRange(buffer.y);
@@ -401,12 +399,12 @@ export class InputHandler extends Disposable implements IInputHandler {
// a halfwidth char any fullwidth shifted there is lost
// and will be set to empty cell
if (bufferRow.loadCell(cols - 1, this._cell).width === 2) {
bufferRow.setDataFromCodePoint(cols - 1, NULL_CELL_CODE, NULL_CELL_WIDTH, curAttr, 0);
bufferRow.setDataFromCodePoint(cols - 1, NULL_CELL_CODE, NULL_CELL_WIDTH, curAttr.fg, curAttr.bg);
}
}
// write current char to buffer and advance cursor
bufferRow.setDataFromCodePoint(buffer.x++, code, chWidth, curAttr, 0);
bufferRow.setDataFromCodePoint(buffer.x++, code, chWidth, curAttr.fg, curAttr.bg);
// fullwidth char - also set next cell to placeholder stub and advance cursor
// for graphemes bigger than fullwidth we can simply loop to zero
@@ -414,7 +412,7 @@ export class InputHandler extends Disposable implements IInputHandler {
if (chWidth > 0) {
while (--chWidth) {
// other than a regular empty cell a cell following a wide char has no width
bufferRow.setDataFromCodePoint(buffer.x++, 0, 0, curAttr, 0);
bufferRow.setDataFromCodePoint(buffer.x++, 0, 0, curAttr.fg, curAttr.bg);
}
}
}
@@ -520,7 +518,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).insertCells(
this._terminal.buffer.x,
params[0] || 1,
this._terminal.buffer.getNullCell(this._terminal.eraseAttr())
this._terminal.buffer.getNullCell(this._terminal.eraseAttrData())
);
this._terminal.updateRange(this._terminal.buffer.y);
}
@@ -694,7 +692,7 @@ export class InputHandler extends Disposable implements IInputHandler {
line.replaceCells(
start,
end,
this._terminal.buffer.getNullCell(this._terminal.eraseAttr())
this._terminal.buffer.getNullCell(this._terminal.eraseAttrData())
);
if (clearWrap) {
line.isWrapped = false;
@@ -817,7 +815,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test: echo -e '\e[44m\e[1L\e[0m'
// blankLine(true) - xterm/linux behavior
buffer.lines.splice(scrollBottomAbsolute - 1, 1);
buffer.lines.splice(row, 0, buffer.getBlankLine(this._terminal.eraseAttr()));
buffer.lines.splice(row, 0, buffer.getBlankLine(this._terminal.eraseAttrData()));
}
// this.maxRange();
@@ -847,7 +845,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// test: echo -e '\e[44m\e[1M\e[0m'
// blankLine(true) - xterm/linux behavior
buffer.lines.splice(row, 1);
buffer.lines.splice(j, 0, buffer.getBlankLine(this._terminal.eraseAttr()));
buffer.lines.splice(j, 0, buffer.getBlankLine(this._terminal.eraseAttrData()));
}
// this.maxRange();
@@ -863,7 +861,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).deleteCells(
this._terminal.buffer.x,
params[0] || 1,
this._terminal.buffer.getNullCell(this._terminal.eraseAttr())
this._terminal.buffer.getNullCell(this._terminal.eraseAttrData())
);
this._terminal.updateRange(this._terminal.buffer.y);
}
@@ -879,7 +877,7 @@ export class InputHandler extends Disposable implements IInputHandler {
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollTop, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(DEFAULT_ATTR));
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(DEFAULT_ATTR_DATA));
}
// this.maxRange();
this._terminal.updateRange(buffer.scrollTop);
@@ -898,7 +896,7 @@ export class InputHandler extends Disposable implements IInputHandler {
while (param--) {
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 1);
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(DEFAULT_ATTR));
buffer.lines.splice(buffer.ybase + buffer.scrollBottom, 0, buffer.getBlankLine(DEFAULT_ATTR_DATA));
}
// this.maxRange();
this._terminal.updateRange(buffer.scrollTop);
@@ -914,7 +912,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._terminal.buffer.lines.get(this._terminal.buffer.y + this._terminal.buffer.ybase).replaceCells(
this._terminal.buffer.x,
this._terminal.buffer.x + (params[0] || 1),
this._terminal.buffer.getNullCell(this._terminal.eraseAttr())
this._terminal.buffer.getNullCell(this._terminal.eraseAttrData())
);
}
@@ -973,7 +971,7 @@ export class InputHandler extends Disposable implements IInputHandler {
line.loadCell(buffer.x - 1, this._cell);
line.replaceCells(buffer.x,
buffer.x + (params[0] || 1),
(this._cell.content !== undefined) ? this._cell : buffer.getNullCell(DEFAULT_ATTR)
(this._cell.content !== undefined) ? this._cell : buffer.getNullCell(DEFAULT_ATTR_DATA)
);
// FIXME: no updateRange here?
}
@@ -1307,7 +1305,7 @@ export class InputHandler extends Disposable implements IInputHandler {
// FALL-THROUGH
case 47: // alt screen buffer
case 1047: // alt screen buffer
this._terminal.buffers.activateAltBuffer(this._terminal.eraseAttr());
this._terminal.buffers.activateAltBuffer(this._terminal.eraseAttrData());
this._terminal.refresh(0, this._terminal.rows - 1);
if (this._terminal.viewport) {
this._terminal.viewport.syncScrollArea();
@@ -1567,127 +1565,128 @@ export class InputHandler extends Disposable implements IInputHandler {
public charAttributes(params: number[]): void {
// Optimize a single SGR0.
if (params.length === 1 && params[0] === 0) {
this._terminal.curAttr = DEFAULT_ATTR;
this._terminal.curAttrData.fg = DEFAULT_ATTR_DATA.fg;
this._terminal.curAttrData.bg = DEFAULT_ATTR_DATA.bg;
return;
}
const l = params.length;
let flags = this._terminal.curAttr >> 18;
let fg = (this._terminal.curAttr >> 9) & 0x1ff;
let bg = this._terminal.curAttr & 0x1ff;
let p;
const attr = this._terminal.curAttrData;
for (let i = 0; i < l; i++) {
p = params[i];
if (p >= 30 && p <= 37) {
// fg color 8
fg = p - 30;
attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
attr.fg |= Attributes.CM_P16 | (p - 30);
} else if (p >= 40 && p <= 47) {
// bg color 8
bg = p - 40;
attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
attr.bg |= Attributes.CM_P16 | (p - 40);
} else if (p >= 90 && p <= 97) {
// fg color 16
p += 8;
fg = p - 90;
attr.fg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
attr.fg |= Attributes.CM_P16 | (p - 90) | 8;
} else if (p >= 100 && p <= 107) {
// bg color 16
p += 8;
bg = p - 100;
attr.bg &= ~(Attributes.CM_MASK | Attributes.PCOLOR_MASK);
attr.bg |= Attributes.CM_P16 | (p - 100) | 8;
} else if (p === 0) {
// default
flags = DEFAULT_ATTR >> 18;
fg = (DEFAULT_ATTR >> 9) & 0x1ff;
bg = DEFAULT_ATTR & 0x1ff;
// flags = 0;
// fg = 0x1ff;
// bg = 0x1ff;
attr.fg = DEFAULT_ATTR_DATA.fg;
attr.bg = DEFAULT_ATTR_DATA.bg;
} else if (p === 1) {
// bold text
flags |= FLAGS.BOLD;
attr.fg |= FgFlags.BOLD;
} else if (p === 3) {
// italic text
flags |= FLAGS.ITALIC;
attr.bg |= BgFlags.ITALIC;
} else if (p === 4) {
// underlined text
flags |= FLAGS.UNDERLINE;
attr.fg |= FgFlags.UNDERLINE;
} else if (p === 5) {
// blink
flags |= FLAGS.BLINK;
attr.fg |= FgFlags.BLINK;
} else if (p === 7) {
// inverse and positive
// test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m'
flags |= FLAGS.INVERSE;
attr.fg |= FgFlags.INVERSE;
} else if (p === 8) {
// invisible
flags |= FLAGS.INVISIBLE;
attr.fg |= FgFlags.INVISIBLE;
} else if (p === 2) {
// dimmed text
flags |= FLAGS.DIM;
attr.bg |= BgFlags.DIM;
} else if (p === 22) {
// not bold nor faint
flags &= ~FLAGS.BOLD;
flags &= ~FLAGS.DIM;
attr.fg &= ~FgFlags.BOLD;
attr.bg &= ~BgFlags.DIM;
} else if (p === 23) {
// not italic
flags &= ~FLAGS.ITALIC;
attr.bg &= ~BgFlags.ITALIC;
} else if (p === 24) {
// not underlined
flags &= ~FLAGS.UNDERLINE;
attr.fg &= ~FgFlags.UNDERLINE;
} else if (p === 25) {
// not blink
flags &= ~FLAGS.BLINK;
attr.fg &= ~FgFlags.BLINK;
} else if (p === 27) {
// not inverse
flags &= ~FLAGS.INVERSE;
attr.fg &= ~FgFlags.INVERSE;
} else if (p === 28) {
// not invisible
flags &= ~FLAGS.INVISIBLE;
attr.fg &= ~FgFlags.INVISIBLE;
} else if (p === 39) {
// reset fg
fg = (DEFAULT_ATTR >> 9) & 0x1ff;
attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
} else if (p === 49) {
// reset bg
bg = DEFAULT_ATTR & 0x1ff;
attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
} else if (p === 38) {
// fg color 256
if (params[i + 1] === 2) {
i += 2;
fg = this._terminal.matchColor(
params[i] & 0xff,
params[i + 1] & 0xff,
params[i + 2] & 0xff);
if (fg === -1) fg = 0x1ff;
attr.fg |= Attributes.CM_RGB;
attr.fg &= ~Attributes.RGB_MASK;
attr.fg |= (params[i] & 0xFF) << Attributes.RED_SHIFT;
attr.fg |= (params[i + 1] & 0xFF) << Attributes.GREEN_SHIFT;
attr.fg |= (params[i + 2] & 0xFF) << Attributes.BLUE_SHIFT;
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
p = params[i] & 0xff;
fg = p;
attr.fg &= ~Attributes.PCOLOR_MASK;
attr.fg |= Attributes.CM_P256 | p;
}
} else if (p === 48) {
// bg color 256
if (params[i + 1] === 2) {
i += 2;
bg = this._terminal.matchColor(
params[i] & 0xff,
params[i + 1] & 0xff,
params[i + 2] & 0xff);
if (bg === -1) bg = 0x1ff;
attr.bg |= Attributes.CM_RGB;
attr.bg &= ~Attributes.RGB_MASK;
attr.bg |= (params[i] & 0xFF) << Attributes.RED_SHIFT;
attr.bg |= (params[i + 1] & 0xFF) << Attributes.GREEN_SHIFT;
attr.bg |= (params[i + 2] & 0xFF) << Attributes.BLUE_SHIFT;
i += 2;
} else if (params[i + 1] === 5) {
i += 2;
p = params[i] & 0xff;
bg = p;
attr.bg &= ~Attributes.PCOLOR_MASK;
attr.bg |= Attributes.CM_P256 | p;
}
} else if (p === 100) {
// reset fg/bg
fg = (DEFAULT_ATTR >> 9) & 0x1ff;
bg = DEFAULT_ATTR & 0x1ff;
attr.fg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
attr.fg |= DEFAULT_ATTR_DATA.fg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
attr.bg &= ~(Attributes.CM_MASK | Attributes.RGB_MASK);
attr.bg |= DEFAULT_ATTR_DATA.bg & (Attributes.PCOLOR_MASK | Attributes.RGB_MASK);
} else {
this._terminal.error('Unknown SGR attribute: %d.', p);
}
}
this._terminal.curAttr = (flags << 18) | (fg << 9) | bg;
}
/**
@@ -1774,7 +1773,7 @@ export class InputHandler extends Disposable implements IInputHandler {
this._terminal.applicationCursor = false;
this._terminal.buffer.scrollTop = 0;
this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
this._terminal.curAttr = DEFAULT_ATTR;
this._terminal.curAttrData = DEFAULT_ATTR_DATA;
this._terminal.buffer.x = this._terminal.buffer.y = 0; // ?
this._terminal.charset = null;
this._terminal.glevel = 0; // ??
@@ -1837,7 +1836,8 @@ export class InputHandler extends Disposable implements IInputHandler {
public saveCursor(params: number[]): void {
this._terminal.buffer.savedX = this._terminal.buffer.x;
this._terminal.buffer.savedY = this._terminal.buffer.y;
this._terminal.buffer.savedCurAttr = this._terminal.curAttr;
this._terminal.buffer.savedCurAttrData.fg = this._terminal.curAttrData.fg;
this._terminal.buffer.savedCurAttrData.bg = this._terminal.curAttrData.bg;
}
@@ -1849,7 +1849,8 @@ export class InputHandler extends Disposable implements IInputHandler {
public restoreCursor(params: number[]): void {
this._terminal.buffer.x = this._terminal.buffer.savedX || 0;
this._terminal.buffer.y = this._terminal.buffer.savedY || 0;
this._terminal.curAttr = this._terminal.buffer.savedCurAttr || DEFAULT_ATTR;
this._terminal.curAttrData.fg = this._terminal.buffer.savedCurAttrData.fg;
this._terminal.curAttrData.bg = this._terminal.buffer.savedCurAttrData.bg;
}