RGB support in buffer and attributes
This commit is contained in:
+77
-76
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user