diff --git a/src/public/Terminal.ts b/src/public/Terminal.ts index ce469b97..3af5162c 100644 --- a/src/public/Terminal.ts +++ b/src/public/Terminal.ts @@ -32,6 +32,7 @@ export class Terminal implements ITerminalApi { public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; } public get element(): HTMLElement { return this._core.element; } + public get screenElement(): HTMLElement { return this._core.screenElement; } public get textarea(): HTMLTextAreaElement { return this._core.textarea; } public get rows(): number { return this._core.rows; } public get cols(): number { return this._core.cols; } diff --git a/src/renderer/LinkRenderLayer.ts b/src/renderer/LinkRenderLayer.ts index c92b10dc..6bba167c 100644 --- a/src/renderer/LinkRenderLayer.ts +++ b/src/renderer/LinkRenderLayer.ts @@ -15,6 +15,7 @@ export class LinkRenderLayer extends BaseRenderLayer { constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) { super(container, 'link', zIndex, true, colors); + // TODO: Need to expose link-related renderer API terminal.linkifier.onLinkHover(e => this._onLinkHover(e)); terminal.linkifier.onLinkLeave(e => this._onLinkLeave(e)); } diff --git a/src/renderer/webgl/GlyphRenderer.ts b/src/renderer/webgl/GlyphRenderer.ts index 9d61b065..de9c0bf7 100644 --- a/src/renderer/webgl/GlyphRenderer.ts +++ b/src/renderer/webgl/GlyphRenderer.ts @@ -5,16 +5,14 @@ import { createProgram, PROJECTION_MATRIX } from './WebglUtils'; import { IRenderDimensions } from '../Types'; -import { ITerminal } from '../../Types'; import WebglCharAtlas from './atlas/WebglCharAtlas'; import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types'; import { INDICIES_PER_CELL } from './WebglRenderer'; import { COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { fill, slice } from './TypedArray'; -import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, CHAR_DATA_CHAR_INDEX } from '../../core/buffer/BufferLine'; -import { IBufferLine } from '../../core/Types'; +import { NULL_CELL_CODE, WHITESPACE_CELL_CODE } from '../../core/buffer/BufferLine'; import { getLuminance } from './ColorUtils'; -import { IColorSet } from 'xterm'; +import { IColorSet, Terminal, IBufferLine } from 'xterm'; interface IVertices { attributes: Float32Array; @@ -97,7 +95,7 @@ export class GlyphRenderer { }; constructor( - private _terminal: ITerminal, + private _terminal: Terminal, private _colors: IColorSet, private _gl: IWebGL2RenderingContext, private _dimensions: IRenderDimensions @@ -185,9 +183,9 @@ export class GlyphRenderer { let rasterizedGlyph: IRasterizedGlyph; if (chars && chars.length > 1) { - rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg, this._terminal.options.enableBold); + rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg, this._terminal.getOption('enableBold')); } else { - rasterizedGlyph = this._atlas.getRasterizedGlyph(code, attr, bg, fg, this._terminal.options.enableBold); + rasterizedGlyph = this._atlas.getRasterizedGlyph(code, attr, bg, fg, this._terminal.getOption('enableBold')); } // Fill empty if no glyph was found @@ -252,8 +250,8 @@ export class GlyphRenderer { private _updateSelectionRange(startCol: number, endCol: number, y: number, model: IRenderModel, bg: number, fg: number): void { const terminal = this._terminal; - const row = y + terminal.buffer.ydisp; - let line: IBufferLine; + const row = y + terminal.buffer.viewportY; + let line: IBufferLine | undefined; for (let x = startCol; x < endCol; x++) { const offset = (y * this._terminal.cols + x) * INDICIES_PER_CELL; // Because the cache uses attr as a lookup key it needs to contain the selection colors as well @@ -262,10 +260,9 @@ export class GlyphRenderer { const code = model.cells[offset]; if (code & COMBINED_CHAR_BIT_MASK) { if (!line) { - line = terminal.buffer.lines.get(row); + line = terminal.buffer.getLine(row); } - const charData = line.get(x); - const chars = charData[CHAR_DATA_CHAR_INDEX]; + const chars = line.getCell(x).char; this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg, chars); } else { this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg); diff --git a/src/renderer/webgl/RectangleRenderer.ts b/src/renderer/webgl/RectangleRenderer.ts index a133abd4..ca4c062c 100644 --- a/src/renderer/webgl/RectangleRenderer.ts +++ b/src/renderer/webgl/RectangleRenderer.ts @@ -3,7 +3,6 @@ * @license MIT */ -import { ITerminal } from '../../Types'; import { IRenderDimensions } from '../Types'; import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils'; import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelectionRenderModel } from './Types'; @@ -11,7 +10,7 @@ import { fill } from './TypedArray'; import { INVERTED_DEFAULT_COLOR } from './atlas/Types'; import { is256Color } from './atlas/CharAtlasUtils'; import { DEFAULT_COLOR } from '../../common/Types'; -import { IColorSet, IColor } from 'xterm'; +import { IColorSet, IColor, Terminal } from 'xterm'; const enum VertexAttribLocations { POSITION = 0, @@ -76,7 +75,7 @@ export class RectangleRenderer { }; constructor( - private _terminal: ITerminal, + private _terminal: Terminal, private _colors: IColorSet, private _gl: IWebGL2RenderingContext, private _dimensions: IRenderDimensions diff --git a/src/renderer/webgl/WebglRenderer.ts b/src/renderer/webgl/WebglRenderer.ts index 27404a8a..2fadebbd 100644 --- a/src/renderer/webgl/WebglRenderer.ts +++ b/src/renderer/webgl/WebglRenderer.ts @@ -17,7 +17,7 @@ import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { Disposable } from '../../common/Lifecycle'; import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, CHAR_DATA_ATTR_INDEX, NULL_CELL_CODE } from '../../core/buffer/BufferLine'; import { DEFAULT_COLOR } from '../../common/Types'; -import { IColorSet } from 'xterm'; +import { IColorSet, Terminal } from 'xterm'; import { getLuminance } from './ColorUtils'; export const INDICIES_PER_CELL = 4; @@ -36,16 +36,20 @@ export class WebglRenderer extends Disposable implements IRenderer { public dimensions: IRenderDimensions; + private _core: ITerminal; + constructor( - private _terminal: ITerminal, + private _terminal: Terminal, private _colors: IColorSet ) { super(); + this._core = (this._terminal as any)._core; + this._applyBgLuminanceBasedSelection(); this._renderLayers = [ - new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._terminal), + new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._core), new CursorRenderLayer(this._terminal.screenElement, 3, this._colors) ]; this.dimensions = { @@ -102,8 +106,8 @@ export class WebglRenderer extends Disposable implements IRenderer { // Clear layers and force a full render this._renderLayers.forEach(l => { - l.setColors(this._terminal, this._colors); - l.reset(this._terminal); + l.setColors(this._core, this._colors); + l.reset(this._core); }); this._rectangleRenderer.setColors(); @@ -117,7 +121,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // and the terminal needs to refreshed if (this._devicePixelRatio !== window.devicePixelRatio) { this._devicePixelRatio = window.devicePixelRatio; - this.onResize(this._terminal.cols, this._terminal.rows); + this.onResize(this._core.cols, this._core.rows); } } @@ -125,11 +129,11 @@ export class WebglRenderer extends Disposable implements IRenderer { // Update character and canvas dimensions this._updateDimensions(devicePixelRatio); - this._model.resize(this._terminal.cols, this._terminal.rows); + this._model.resize(this._core.cols, this._core.rows); this._rectangleRenderer.onResize(); // Resize all render layers - this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions)); + this._renderLayers.forEach(l => l.resize(this._core, this.dimensions)); // Resize the canvas this._canvas.width = this.dimensions.scaledCanvasWidth; @@ -151,15 +155,15 @@ export class WebglRenderer extends Disposable implements IRenderer { } public onBlur(): void { - this._renderLayers.forEach(l => l.onBlur(this._terminal)); + this._renderLayers.forEach(l => l.onBlur(this._core)); } public onFocus(): void { - this._renderLayers.forEach(l => l.onFocus(this._terminal)); + this._renderLayers.forEach(l => l.onFocus(this._core)); } public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { - this._renderLayers.forEach(l => l.onSelectionChanged(this._terminal, start, end, columnSelectMode)); + this._renderLayers.forEach(l => l.onSelectionChanged(this._core, start, end, columnSelectMode)); this._updateSelectionModel(start, end); @@ -167,15 +171,15 @@ export class WebglRenderer extends Disposable implements IRenderer { this._glyphRenderer.updateSelection(this._model, columnSelectMode); // TODO: #2102 Should this move to RenderCoordinator? - this._terminal.refresh(0, this._terminal.rows - 1); + this._core.refresh(0, this._core.rows - 1); } public onCursorMove(): void { - this._renderLayers.forEach(l => l.onCursorMove(this._terminal)); + this._renderLayers.forEach(l => l.onCursorMove(this._core)); } public onOptionsChanged(): void { - this._renderLayers.forEach(l => l.onOptionsChanged(this._terminal)); + this._renderLayers.forEach(l => l.onOptionsChanged(this._core)); this._updateDimensions(); this._refreshCharAtlas(); } @@ -200,7 +204,7 @@ export class WebglRenderer extends Disposable implements IRenderer { } public clear(): void { - this._renderLayers.forEach(l => l.reset(this._terminal)); + this._renderLayers.forEach(l => l.reset(this._core)); } public registerCharacterJoiner(handler: CharacterJoinerHandler): number { @@ -213,7 +217,7 @@ export class WebglRenderer extends Disposable implements IRenderer { public renderRows(start: number, end: number): void { // Update render layers - this._renderLayers.forEach(l => l.onGridChanged(this._terminal, start, end)); + this._renderLayers.forEach(l => l.onGridChanged(this._core, start, end)); // Tell renderer the frame is beginning if (this._glyphRenderer.beginFrame()) { @@ -229,7 +233,7 @@ export class WebglRenderer extends Disposable implements IRenderer { } private _updateModel(start: number, end: number): void { - const terminal = this._terminal; + const terminal = this._core; for (let y = start; y <= end; y++) { const row = y + terminal.buffer.ydisp; @@ -288,7 +292,7 @@ export class WebglRenderer extends Disposable implements IRenderer { } private _updateSelectionModel(start: [number, number], end: [number, number]): void { - const terminal = this._terminal; + const terminal = this._core; // Selection does not exist if (!start || !end || (start[0] === end[0] && start[1] === end[1])) { @@ -322,7 +326,7 @@ export class WebglRenderer extends Disposable implements IRenderer { */ private _updateDimensions(devicePixelRatio: number = window.devicePixelRatio): void { // Perform a new measure if the CharMeasure dimensions are not yet available - if (!this._terminal.charMeasure.width || !this._terminal.charMeasure.height) { + if (!this._core.charMeasure.width || !this._core.charMeasure.height) { return; } @@ -333,34 +337,34 @@ export class WebglRenderer extends Disposable implements IRenderer { // NOTE: ceil fixes sometime, floor does others :s - this.dimensions.scaledCharWidth = Math.floor(this._terminal.charMeasure.width * devicePixelRatio); + this.dimensions.scaledCharWidth = Math.floor(this._core.charMeasure.width * devicePixelRatio); // Calculate the scaled character height. Height is ceiled in case // devicePixelRatio is a floating point number in order to ensure there is // enough space to draw the character to the cell. - this.dimensions.scaledCharHeight = Math.ceil(this._terminal.charMeasure.height * devicePixelRatio); + this.dimensions.scaledCharHeight = Math.ceil(this._core.charMeasure.height * devicePixelRatio); // Calculate the scaled cell height, if lineHeight is not 1 then the value // will be floored because since lineHeight can never be lower then 1, there // is a guarentee that the scaled line height will always be larger than // scaled char height. - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight); + this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._core.options.lineHeight); // Calculate the y coordinate within a cell that text should draw from in // order to draw in the center of a cell. - this.dimensions.scaledCharTop = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); + this.dimensions.scaledCharTop = this._core.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); // Calculate the scaled cell width, taking the letterSpacing into account. - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing); + this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._core.options.letterSpacing); // Calculate the x coordinate with a cell that text should draw from in // order to draw in the center of a cell. - this.dimensions.scaledCharLeft = Math.floor(this._terminal.options.letterSpacing / 2); + this.dimensions.scaledCharLeft = Math.floor(this._core.options.letterSpacing / 2); // Recalculate the canvas dimensions; scaled* define the actual number of // pixel in the canvas - this.dimensions.scaledCanvasHeight = this._terminal.rows * this.dimensions.scaledCellHeight; - this.dimensions.scaledCanvasWidth = this._terminal.cols * this.dimensions.scaledCellWidth; + this.dimensions.scaledCanvasHeight = this._core.rows * this.dimensions.scaledCellHeight; + this.dimensions.scaledCanvasWidth = this._core.cols * this.dimensions.scaledCellWidth; // The the size of the canvas on the page. It's very important that this // rounds to nearest integer and not ceils as browsers often set diff --git a/src/renderer/webgl/WebglRendererAddon.ts b/src/renderer/webgl/WebglRendererAddon.ts index 764caa0f..6c835ba8 100644 --- a/src/renderer/webgl/WebglRendererAddon.ts +++ b/src/renderer/webgl/WebglRendererAddon.ts @@ -16,8 +16,7 @@ export class WebglRendererAddon implements ITerminalAddon { throw new Error('Cannot activate WebglRendererAddon before Terminal.open'); } this._terminal = terminal; - const core = (terminal as any)._core; - this._terminal.setRenderer(new WebglRenderer(core, core._colorManager.colors)); + this._terminal.setRenderer(new WebglRenderer(terminal, (terminal as any)._core._colorManager.colors)); } public dispose(): void { diff --git a/src/renderer/webgl/atlas/CharAtlasCache.ts b/src/renderer/webgl/atlas/CharAtlasCache.ts index 05bdadc2..8d8459fd 100644 --- a/src/renderer/webgl/atlas/CharAtlasCache.ts +++ b/src/renderer/webgl/atlas/CharAtlasCache.ts @@ -3,19 +3,18 @@ * @license MIT */ -import { ITerminal } from '../../../Types'; import { generateConfig, configEquals } from './CharAtlasUtils'; import BaseCharAtlas from './BaseCharAtlas'; import WebglCharAtlas from './WebglCharAtlas'; import { ICharAtlasConfig } from './Types'; -import { IColorSet } from 'xterm'; +import { IColorSet, Terminal } from 'xterm'; interface ICharAtlasCacheEntry { atlas: BaseCharAtlas; config: ICharAtlasConfig; // N.B. This implementation potentially holds onto copies of the terminal forever, so // this may cause memory leaks. - ownedBy: ITerminal[]; + ownedBy: Terminal[]; } const charAtlasCache: ICharAtlasCacheEntry[] = []; @@ -27,7 +26,7 @@ const charAtlasCache: ICharAtlasCacheEntry[] = []; * @param colors The colors to use. */ export function acquireCharAtlas( - terminal: ITerminal, + terminal: Terminal, colors: IColorSet, scaledCharWidth: number, scaledCharHeight: number @@ -76,7 +75,7 @@ export function acquireCharAtlas( * Removes a terminal reference from the cache, allowing its memory to be freed. * @param terminal The terminal to remove. */ -export function removeTerminalFromCache(terminal: ITerminal): void { +export function removeTerminalFromCache(terminal: Terminal): void { for (let i = 0; i < charAtlasCache.length; i++) { const index = charAtlasCache[i].ownedBy.indexOf(terminal); if (index !== -1) { diff --git a/src/renderer/webgl/atlas/CharAtlasUtils.ts b/src/renderer/webgl/atlas/CharAtlasUtils.ts index 855e32c8..2bda420f 100644 --- a/src/renderer/webgl/atlas/CharAtlasUtils.ts +++ b/src/renderer/webgl/atlas/CharAtlasUtils.ts @@ -3,12 +3,11 @@ * @license MIT */ -import { ITerminal } from '../../../Types'; import { ICharAtlasConfig } from './Types'; import { DEFAULT_COLOR } from '../../../common/Types'; -import { IColorSet } from 'xterm'; +import { IColorSet, Terminal, FontWeight } from 'xterm'; -export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig { +export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig { // null out some fields that don't matter const clonedColors: IColorSet = { foreground: colors.foreground, @@ -21,15 +20,14 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number ansi: colors.ansi.slice(0, 16) }; return { - type: terminal.options.experimentalCharAtlas, devicePixelRatio: window.devicePixelRatio, scaledCharWidth, scaledCharHeight, - fontFamily: terminal.options.fontFamily, - fontSize: terminal.options.fontSize, - fontWeight: terminal.options.fontWeight, - fontWeightBold: terminal.options.fontWeightBold, - allowTransparency: terminal.options.allowTransparency, + fontFamily: terminal.getOption('fontFamily'), + fontSize: terminal.getOption('fontSize'), + fontWeight: terminal.getOption('fontWeight') as FontWeight, + fontWeightBold: terminal.getOption('fontWeightBold') as FontWeight, + allowTransparency: terminal.getOption('allowTransparency'), colors: clonedColors }; } @@ -40,8 +38,7 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean return false; } } - return a.type === b.type && - a.devicePixelRatio === b.devicePixelRatio && + return a.devicePixelRatio === b.devicePixelRatio && a.fontFamily === b.fontFamily && a.fontSize === b.fontSize && a.fontWeight === b.fontWeight && diff --git a/src/renderer/webgl/atlas/Types.ts b/src/renderer/webgl/atlas/Types.ts index ee6dc665..1df4f82d 100644 --- a/src/renderer/webgl/atlas/Types.ts +++ b/src/renderer/webgl/atlas/Types.ts @@ -21,7 +21,6 @@ export interface IGlyphIdentifier { } export interface ICharAtlasConfig { - type: 'none' | 'static' | 'dynamic' | 'webgl'; devicePixelRatio: number; fontSize: number; fontFamily: string; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 7d79d959..8712c3d8 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -895,6 +895,11 @@ declare module 'xterm' { * (EXPERIMENTAL) */ setRenderer(renderer: any): void; + screenElement: HTMLElement; + } + + export namespace Renderer { + const DEFAULT_COLOR: number; } /**