Merge branch 'master' into pr/jerch/1895
This commit is contained in:
@@ -241,7 +241,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
this._ctx.fillText(
|
||||
cell.getChars(),
|
||||
x * this._scaledCellWidth + this._scaledCharLeft,
|
||||
(y + 0.5) * this._scaledCellHeight + this._scaledCharTop);
|
||||
y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -342,7 +342,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
this._ctx.fillText(
|
||||
cell.getChars(),
|
||||
x * this._scaledCellWidth + this._scaledCharLeft,
|
||||
(y + 0.5) * this._scaledCellHeight + this._scaledCharTop);
|
||||
y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2);
|
||||
this._ctx.restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
|
||||
|
||||
private _characterJoiners: ICharacterJoiner[] = [];
|
||||
private _nextCharacterJoinerId: number = 0;
|
||||
private _cell: CellData = new CellData();
|
||||
private _workCell: CellData = new CellData();
|
||||
|
||||
constructor(private _terminal: ITerminal) {
|
||||
}
|
||||
@@ -53,19 +53,19 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
|
||||
let rangeStartColumn = 0;
|
||||
let currentStringIndex = 0;
|
||||
let rangeStartStringIndex = 0;
|
||||
let rangeAttrFG = line.getFG(0);
|
||||
let rangeAttrBG = line.getBG(0);
|
||||
let rangeAttrFG = line.getFg(0);
|
||||
let rangeAttrBG = line.getBg(0);
|
||||
|
||||
for (let x = 0; x < line.getTrimmedLength(); x++) {
|
||||
line.loadCell(x, this._cell);
|
||||
line.loadCell(x, this._workCell);
|
||||
|
||||
if (this._cell.getWidth() === 0) {
|
||||
if (this._workCell.getWidth() === 0) {
|
||||
// If this character is of width 0, skip it.
|
||||
continue;
|
||||
}
|
||||
|
||||
// End of range
|
||||
if (this._cell.fg !== rangeAttrFG || this._cell.bg !== rangeAttrBG) {
|
||||
if (this._workCell.fg !== rangeAttrFG || this._workCell.bg !== rangeAttrBG) {
|
||||
// If we ended up with a sequence of more than one character,
|
||||
// look for ranges to join.
|
||||
if (x - rangeStartColumn > 1) {
|
||||
@@ -84,11 +84,11 @@ export class CharacterJoinerRegistry implements ICharacterJoinerRegistry {
|
||||
// Reset our markers for a new range.
|
||||
rangeStartColumn = x;
|
||||
rangeStartStringIndex = currentStringIndex;
|
||||
rangeAttrFG = this._cell.fg;
|
||||
rangeAttrBG = this._cell.bg;
|
||||
rangeAttrFG = this._workCell.fg;
|
||||
rangeAttrBG = this._workCell.bg;
|
||||
}
|
||||
|
||||
currentStringIndex += this._cell.getChars().length || WHITESPACE_CELL_CHAR.length;
|
||||
currentStringIndex += this._workCell.getChars().length || WHITESPACE_CELL_CHAR.length;
|
||||
}
|
||||
|
||||
// Process any trailing ranges.
|
||||
|
||||
@@ -70,7 +70,7 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
// Detect whether IntersectionObserver is detected and enable renderer pause
|
||||
// and resume based on terminal visibility if so
|
||||
if ('IntersectionObserver' in window) {
|
||||
const observer = new IntersectionObserver(e => this.onIntersectionChange(e[0]), { threshold: 0 });
|
||||
const observer = new IntersectionObserver(e => this.onIntersectionChange(e[e.length - 1]), { threshold: 0 });
|
||||
observer.observe(this._terminal.element);
|
||||
this.register({ dispose: () => observer.disconnect() });
|
||||
}
|
||||
@@ -85,6 +85,7 @@ export class Renderer extends EventEmitter implements IRenderer {
|
||||
this._isPaused = entry.intersectionRatio === 0;
|
||||
if (!this._isPaused && this._needsFullRefresh) {
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
this._needsFullRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ export class SelectionRenderLayer extends BaseRenderLayer {
|
||||
|
||||
// Selection does not exist
|
||||
if (!start || !end) {
|
||||
this._clearState();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types'
|
||||
import { CharData, ITerminal, ICellData } from '../Types';
|
||||
import { GridCache } from './GridCache';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { CellData, AttributeData, Content } from '../BufferLine';
|
||||
import { CellData, AttributeData, ContentMasks, WIDTH_MASK_SHIFT } from '../BufferLine';
|
||||
|
||||
/**
|
||||
* This CharData looks like a null character, which will forc a clear and render
|
||||
@@ -23,7 +23,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
private _characterFont: string;
|
||||
private _characterOverlapCache: { [key: string]: boolean } = {};
|
||||
private _characterJoinerRegistry: ICharacterJoinerRegistry;
|
||||
private _cell = new CellData();
|
||||
private _workCell = new CellData();
|
||||
|
||||
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, characterJoinerRegistry: ICharacterJoinerRegistry, alpha: boolean) {
|
||||
super(container, 'text', zIndex, alpha, colors);
|
||||
@@ -67,8 +67,8 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
const line = terminal.buffer.lines.get(row);
|
||||
const joinedRanges = joinerRegistry ? joinerRegistry.getJoinedCharacters(row) : [];
|
||||
for (let x = 0; x < terminal.cols; x++) {
|
||||
line.loadCell(x, this._cell);
|
||||
let cell = this._cell;
|
||||
line.loadCell(x, this._workCell);
|
||||
let cell = this._workCell;
|
||||
|
||||
// If true, indicates that the current character(s) to draw were joined.
|
||||
let isJoined = false;
|
||||
@@ -96,8 +96,8 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
0xFFFFFF
|
||||
]);
|
||||
// hacky: patch attrs
|
||||
cell.fg = this._cell.fg;
|
||||
cell.bg = this._cell.bg;
|
||||
cell.fg = this._workCell.fg;
|
||||
cell.bg = this._workCell.bg;
|
||||
|
||||
// Skip over the cells occupied by this range in the loop
|
||||
lastCharX = range[1] - 1;
|
||||
@@ -117,8 +117,8 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
// this._state.cache[x][y] = OVERLAP_OWNED_CHAR_DATA;
|
||||
if (lastCharX < line.length - 1 && line.getCodePoint(lastCharX + 1) === NULL_CELL_CODE) {
|
||||
// patch width to 2
|
||||
cell.content &= ~Content.WIDTH_MASK;
|
||||
cell.content |= 2 << Content.WIDTH_SHIFT;
|
||||
cell.content &= ~ContentMasks.WIDTH;
|
||||
cell.content |= 2 << WIDTH_MASK_SHIFT;
|
||||
// this._clearChar(x + 1, y);
|
||||
// The overlapping char's char data will force a clear and render when the
|
||||
// overlapping char is no longer to the left of the character and also when
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ITheme } from 'xterm';
|
||||
import { EventEmitter } from '../../common/EventEmitter';
|
||||
import { ColorManager } from '../ColorManager';
|
||||
import { RenderDebouncer } from '../../ui/RenderDebouncer';
|
||||
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory';
|
||||
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory';
|
||||
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
||||
|
||||
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
|
||||
@@ -75,7 +75,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
||||
this._updateDimensions();
|
||||
|
||||
this._renderDebouncer = new RenderDebouncer(this._terminal, this._renderRows.bind(this));
|
||||
this._rowFactory = new DomRendererRowFactory(document);
|
||||
this._rowFactory = new DomRendererRowFactory(_terminal.options, document);
|
||||
|
||||
this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass);
|
||||
this._terminal.screenElement.appendChild(this._rowContainer);
|
||||
@@ -165,12 +165,22 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
||||
`${this._terminalSelector} span.${ITALIC_CLASS} {` +
|
||||
` font-style: italic;` +
|
||||
`}`;
|
||||
// Blink animation
|
||||
styles +=
|
||||
`@keyframes blink {` +
|
||||
` 0 % { opacity: 1.0; }` +
|
||||
` 50% { opacity: 0.0; }` +
|
||||
` 100 % { opacity: 1.0; }` +
|
||||
`}`;
|
||||
// Cursor
|
||||
styles +=
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS} {` +
|
||||
` outline: 1px solid ${this.colorManager.colors.cursor.css};` +
|
||||
` outline-offset: -1px;` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_BLINK_CLASS} {` +
|
||||
` animation: blink 1s step-end infinite;` +
|
||||
`}` +
|
||||
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` +
|
||||
` background-color: ${this.colorManager.colors.cursor.css};` +
|
||||
` color: ${this.colorManager.colors.cursorAccent.css};` +
|
||||
@@ -328,6 +338,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
||||
|
||||
const cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y;
|
||||
const cursorX = this._terminal.buffer.x;
|
||||
const cursorBlink = this._terminal.options.cursorBlink;
|
||||
|
||||
for (let y = start; y <= end; y++) {
|
||||
const rowElement = this._rowElements[y];
|
||||
@@ -336,7 +347,7 @@ export class DomRenderer extends EventEmitter implements IRenderer {
|
||||
const row = y + terminal.buffer.ydisp;
|
||||
const lineData = terminal.buffer.lines.get(row);
|
||||
const cursorStyle = terminal.options.cursorStyle;
|
||||
rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, this.dimensions.actualCellWidth, terminal.cols));
|
||||
rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, terminal.cols));
|
||||
}
|
||||
|
||||
this._terminal.emit('refresh', {start, end});
|
||||
|
||||
@@ -8,22 +8,27 @@ import { assert } from 'chai';
|
||||
import { DomRendererRowFactory } from './DomRendererRowFactory';
|
||||
import { DEFAULT_ATTR, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR_DATA } from '../../Buffer';
|
||||
import { BufferLine, CellData, FgFlags, BgFlags, Attributes } from '../../BufferLine';
|
||||
import { IBufferLine } from '../../Types';
|
||||
import { IBufferLine, ITerminalOptions } from '../../Types';
|
||||
|
||||
describe('DomRendererRowFactory', () => {
|
||||
let dom: jsdom.JSDOM;
|
||||
const options: ITerminalOptions = {};
|
||||
let rowFactory: DomRendererRowFactory;
|
||||
let lineData: IBufferLine;
|
||||
|
||||
beforeEach(() => {
|
||||
dom = new jsdom.JSDOM('');
|
||||
rowFactory = new DomRendererRowFactory(dom.window.document);
|
||||
|
||||
options.enableBold = true;
|
||||
options.drawBoldTextInBrightColors = true;
|
||||
|
||||
rowFactory = new DomRendererRowFactory(options, dom.window.document);
|
||||
lineData = createEmptyLineData(2);
|
||||
});
|
||||
|
||||
describe('createRow', () => {
|
||||
it('should not create anything for an empty row', () => {
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
''
|
||||
);
|
||||
@@ -33,7 +38,7 @@ describe('DomRendererRowFactory', () => {
|
||||
lineData.setCell(0, CellData.fromCharData([DEFAULT_ATTR, '語', 2, '語'.charCodeAt(0)]));
|
||||
// There should be no element for the following "empty" cell
|
||||
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, '', 0, undefined]));
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span style="width: 10px;">語</span>'
|
||||
);
|
||||
@@ -41,17 +46,24 @@ describe('DomRendererRowFactory', () => {
|
||||
|
||||
it('should add class for cursor and cursor style', () => {
|
||||
for (const style of ['block', 'bar', 'underline']) {
|
||||
const fragment = rowFactory.createRow(lineData, true, style, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, true, style, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
`<span class="xterm-cursor xterm-cursor-${style}"> </span>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('should add class for cursor blink', () => {
|
||||
const fragment = rowFactory.createRow(lineData, true, 'block', 0, true, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
`<span class="xterm-cursor xterm-cursor-blink xterm-cursor-block"> </span>`
|
||||
);
|
||||
});
|
||||
|
||||
it('should not render cells that go beyond the terminal\'s columns', () => {
|
||||
lineData.setCell(0, CellData.fromCharData([DEFAULT_ATTR, 'a', 1, 'a'.charCodeAt(0)]));
|
||||
lineData.setCell(1, CellData.fromCharData([DEFAULT_ATTR, 'b', 1, 'b'.charCodeAt(0)]));
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 1);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 1);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span>a</span>'
|
||||
);
|
||||
@@ -62,7 +74,7 @@ describe('DomRendererRowFactory', () => {
|
||||
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
|
||||
cell.fg = DEFAULT_ATTR_DATA.fg | FgFlags.BOLD;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span class="xterm-bold">a</span>'
|
||||
);
|
||||
@@ -72,7 +84,7 @@ describe('DomRendererRowFactory', () => {
|
||||
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
|
||||
cell.bg = DEFAULT_ATTR_DATA.bg | BgFlags.ITALIC;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span class="xterm-italic">a</span>'
|
||||
);
|
||||
@@ -85,7 +97,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.fg &= ~Attributes.PCOLOR_MASK;
|
||||
cell.fg |= i;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
`<span class="xterm-fg-${i}">a</span>`
|
||||
);
|
||||
@@ -99,7 +111,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.bg &= ~Attributes.PCOLOR_MASK;
|
||||
cell.bg |= i;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
`<span class="xterm-bg-${i}">a</span>`
|
||||
);
|
||||
@@ -111,7 +123,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.fg |= Attributes.CM_P16 | 2 | FgFlags.INVERSE;
|
||||
cell.bg |= Attributes.CM_P16 | 1;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span class="xterm-bg-2 xterm-fg-1">a</span>'
|
||||
);
|
||||
@@ -122,7 +134,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.fg |= FgFlags.INVERSE;
|
||||
cell.bg |= Attributes.CM_P16 | 1;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span class="xterm-bg-257 xterm-fg-1">a</span>'
|
||||
);
|
||||
@@ -132,7 +144,7 @@ describe('DomRendererRowFactory', () => {
|
||||
const cell = CellData.fromCharData([0, 'a', 1, 'a'.charCodeAt(0)]);
|
||||
cell.fg |= Attributes.CM_P16 | 1 | FgFlags.INVERSE;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span class="xterm-bg-1 xterm-fg-257">a</span>'
|
||||
);
|
||||
@@ -145,7 +157,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.fg &= ~Attributes.PCOLOR_MASK;
|
||||
cell.fg |= i;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
`<span class="xterm-bold xterm-fg-${i + 8}">a</span>`
|
||||
);
|
||||
@@ -157,7 +169,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.fg |= Attributes.CM_RGB | 1 << 16 | 2 << 8 | 3;
|
||||
cell.bg |= Attributes.CM_RGB | 4 << 16 | 5 << 8 | 6;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span style="color:rgb(1,2,3);background-color:rgb(4,5,6);">a</span>'
|
||||
);
|
||||
@@ -168,7 +180,7 @@ describe('DomRendererRowFactory', () => {
|
||||
cell.fg |= Attributes.CM_RGB | 1 << 16 | 2 << 8 | 3 | FgFlags.INVERSE;
|
||||
cell.bg |= Attributes.CM_RGB | 4 << 16 | 5 << 8 | 6;
|
||||
lineData.setCell(0, cell);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, 5, 20);
|
||||
const fragment = rowFactory.createRow(lineData, false, undefined, 0, false, 5, 20);
|
||||
assert.equal(getFragmentHtml(fragment),
|
||||
'<span style="background-color:rgb(1,2,3);color:rgb(4,5,6);">a</span>'
|
||||
);
|
||||
|
||||
@@ -4,25 +4,28 @@
|
||||
*/
|
||||
|
||||
import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../Buffer';
|
||||
import { IBufferLine } from '../../Types';
|
||||
import { IBufferLine, ITerminalOptions } from '../../Types';
|
||||
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
|
||||
import { CellData, AttributeData } from '../../BufferLine';
|
||||
|
||||
export const BOLD_CLASS = 'xterm-bold';
|
||||
export const ITALIC_CLASS = 'xterm-italic';
|
||||
export const CURSOR_CLASS = 'xterm-cursor';
|
||||
export const CURSOR_BLINK_CLASS = 'xterm-cursor-blink';
|
||||
export const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block';
|
||||
export const CURSOR_STYLE_BAR_CLASS = 'xterm-cursor-bar';
|
||||
export const CURSOR_STYLE_UNDERLINE_CLASS = 'xterm-cursor-underline';
|
||||
|
||||
export class DomRendererRowFactory {
|
||||
private _cell: CellData = new CellData();
|
||||
private _workCell: CellData = new CellData();
|
||||
|
||||
constructor(
|
||||
private _terminalOptions: ITerminalOptions,
|
||||
private _document: Document
|
||||
) {
|
||||
}
|
||||
|
||||
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cellWidth: number, cols: number): DocumentFragment {
|
||||
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number): DocumentFragment {
|
||||
const fragment = this._document.createDocumentFragment();
|
||||
|
||||
// Find the line length first, this prevents the need to output a bunch of
|
||||
@@ -32,15 +35,15 @@ export class DomRendererRowFactory {
|
||||
// the viewport).
|
||||
let lineLength = 0;
|
||||
for (let x = Math.min(lineData.length, cols) - 1; x >= 0; x--) {
|
||||
if (lineData.loadCell(x, this._cell).getCode() !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) {
|
||||
if (lineData.loadCell(x, this._workCell).getCode() !== NULL_CELL_CODE || (isCursorRow && x === cursorX)) {
|
||||
lineLength = x + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let x = 0; x < lineLength; x++) {
|
||||
lineData.loadCell(x, this._cell);
|
||||
const width = this._cell.getWidth();
|
||||
lineData.loadCell(x, this._workCell);
|
||||
const width = this._workCell.getWidth();
|
||||
|
||||
// The character to the left is a wide character, drawing is owned by the char at x-1
|
||||
if (width === 0) {
|
||||
@@ -55,6 +58,10 @@ export class DomRendererRowFactory {
|
||||
if (isCursorRow && x === cursorX) {
|
||||
charElement.classList.add(CURSOR_CLASS);
|
||||
|
||||
if (cursorBlink) {
|
||||
charElement.classList.add(CURSOR_BLINK_CLASS);
|
||||
}
|
||||
|
||||
switch (cursorStyle) {
|
||||
case 'bar':
|
||||
charElement.classList.add(CURSOR_STYLE_BAR_CLASS);
|
||||
@@ -68,26 +75,27 @@ export class DomRendererRowFactory {
|
||||
}
|
||||
}
|
||||
|
||||
if (this._cell.isBold()) {
|
||||
if (this._workCell.isBold() && this._terminalOptions.enableBold) {
|
||||
charElement.classList.add(BOLD_CLASS);
|
||||
}
|
||||
|
||||
if (this._cell.isItalic()) {
|
||||
if (this._workCell.isItalic()) {
|
||||
charElement.classList.add(ITALIC_CLASS);
|
||||
}
|
||||
|
||||
charElement.textContent = this._cell.getChars() || WHITESPACE_CELL_CHAR;
|
||||
charElement.textContent = this._workCell.getChars() || WHITESPACE_CELL_CHAR;
|
||||
|
||||
const swapColor = this._cell.isInverse();
|
||||
const swapColor = this._workCell.isInverse();
|
||||
|
||||
// fg
|
||||
if (this._cell.isFgRGB()) {
|
||||
if (this._workCell.isFgRGB()) {
|
||||
let style = charElement.getAttribute('style') || '';
|
||||
style += `${swapColor ? 'background-' : ''}color:rgb(${(AttributeData.toColorRGB(this._cell.getFgColor())).join(',')});`;
|
||||
style += `${swapColor ? 'background-' : ''}color:rgb(${(AttributeData.toColorRGB(this._workCell.getFgColor())).join(',')});`;
|
||||
charElement.setAttribute('style', style);
|
||||
} else if (this._cell.isFgPalette()) {
|
||||
let fg = this._cell.getFgColor();
|
||||
if (this._cell.isBold() && fg < 8 && !swapColor) {
|
||||
} else if (this._workCell.isFgPalette()) {
|
||||
let fg = this._workCell.getFgColor();
|
||||
if (this._workCell.isBold() && fg < 8 && !swapColor &&
|
||||
this._terminalOptions.enableBold && this._terminalOptions.drawBoldTextInBrightColors) {
|
||||
fg += 8;
|
||||
}
|
||||
charElement.classList.add(`xterm-${swapColor ? 'b' : 'f'}g-${fg}`);
|
||||
@@ -96,12 +104,12 @@ export class DomRendererRowFactory {
|
||||
}
|
||||
|
||||
// bg
|
||||
if (this._cell.isBgRGB()) {
|
||||
if (this._workCell.isBgRGB()) {
|
||||
let style = charElement.getAttribute('style') || '';
|
||||
style += `${swapColor ? '' : 'background-'}color:rgb(${(AttributeData.toColorRGB(this._cell.getBgColor())).join(',')});`;
|
||||
style += `${swapColor ? '' : 'background-'}color:rgb(${(AttributeData.toColorRGB(this._workCell.getBgColor())).join(',')});`;
|
||||
charElement.setAttribute('style', style);
|
||||
} else if (this._cell.isBgPalette()) {
|
||||
charElement.classList.add(`xterm-${swapColor ? 'f' : 'b'}g-${this._cell.getBgColor()}`);
|
||||
} else if (this._workCell.isBgPalette()) {
|
||||
charElement.classList.add(`xterm-${swapColor ? 'f' : 'b'}g-${this._workCell.getBgColor()}`);
|
||||
} else if (swapColor) {
|
||||
charElement.classList.add(`xterm-fg-${INVERTED_DEFAULT_COLOR}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user