diff --git a/src/Interfaces.ts b/src/Interfaces.ts index 745dd87a..b6ba08db 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -299,7 +299,7 @@ export interface IInputHandler { export interface ITheme { foreground?: string; background?: string; - // cursor?: string; + cursor?: string; black?: string; red?: string; green?: string; diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 3da7aadc..fb78e1d2 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -1,6 +1,6 @@ import { IRenderLayer, IColorSet } from './Interfaces'; import { ITerminal, ITerminalOptions } from '../Interfaces'; -import { acquireCharAtlas } from '../utils/CharAtlas'; +import { acquireCharAtlas } from './CharAtlas'; export const INVERTED_DEFAULT_COLOR = -1; @@ -94,6 +94,15 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._ctx.clearRect(startCol * this.scaledCharWidth, startRow * this.scaledCharHeight, colWidth * this.scaledCharWidth, colHeight * this.scaledCharHeight); } + protected drawCharTrueColor(terminal: ITerminal, char: string, code: number, x: number, y: number, color: string): void { + this._ctx.save(); + this._ctx.font = `${terminal.options.fontSize * window.devicePixelRatio}px ${terminal.options.fontFamily}`; + this._ctx.textBaseline = 'top'; + this._ctx.fillStyle = color; + this._ctx.fillText(char, x * this.scaledCharWidth, y * this.scaledCharHeight); + this._ctx.restore(); + } + protected drawChar(terminal: ITerminal, char: string, code: number, x: number, y: number, fg: number, underline: boolean = false): void { let colorIndex = 0; if (fg < 256) { @@ -105,13 +114,13 @@ export abstract class BaseRenderLayer implements IRenderLayer { code * this.scaledCharWidth, colorIndex * this.scaledCharHeight, this.scaledCharWidth, this.scaledCharHeight, x * this.scaledCharWidth, y * this.scaledCharHeight, this.scaledCharWidth, this.scaledCharHeight); } else { - this._drawUncachedChar(terminal, char, fg, x, y, this.scaledCharWidth, this.scaledCharHeight); + this._drawUncachedChar(terminal, char, fg, x, y); } // This draws the atlas (for debugging purposes) // this._ctx.drawImage(BaseRenderLayer._charAtlas, 0, 0); } - private _drawUncachedChar(terminal: ITerminal, char: string, fg: number, x: number, y: number, scaledCharWidth: number, scaledCharHeight: number): void { + private _drawUncachedChar(terminal: ITerminal, char: string, fg: number, x: number, y: number): void { this._ctx.save(); this._ctx.font = `${terminal.options.fontSize * window.devicePixelRatio}px ${terminal.options.fontFamily}`; this._ctx.textBaseline = 'top'; @@ -125,7 +134,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { this._ctx.fillStyle = this.colors.foreground; } - this._ctx.fillText(char, x * scaledCharWidth, y * scaledCharHeight); + this._ctx.fillText(char, x * this.scaledCharWidth, y * this.scaledCharHeight); this._ctx.restore(); } } diff --git a/src/utils/CharAtlas.ts b/src/renderer/CharAtlas.ts similarity index 97% rename from src/utils/CharAtlas.ts rename to src/renderer/CharAtlas.ts index 18398efc..e71d8d5a 100644 --- a/src/utils/CharAtlas.ts +++ b/src/renderer/CharAtlas.ts @@ -63,7 +63,8 @@ export function acquireCharAtlas(terminal: ITerminal, colors: IColorSet): Promis function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig { const clonedColors = { foreground: colors.foreground, - background: colors.background, + background: null, + cursor: null, ansi: colors.ansi.slice(0, 16) }; return { @@ -85,8 +86,7 @@ function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean { a.fontSize === b.fontSize && a.scaledCharWidth === b.scaledCharWidth && a.scaledCharHeight === b.scaledCharHeight && - a.colors.foreground === b.colors.foreground && - a.colors.background === b.colors.background; + a.colors.foreground === b.colors.foreground; } class CharAtlasGenerator { diff --git a/src/renderer/ColorManager.ts b/src/renderer/ColorManager.ts index ca8015a2..341e4ca5 100644 --- a/src/renderer/ColorManager.ts +++ b/src/renderer/ColorManager.ts @@ -77,6 +77,7 @@ export class ColorManager { this.colors = { foreground: '#ffffff', background: '#000000', + cursor: '#ffffff', ansi: generate256Colors(DEFAULT_ANSI_COLORS) }; } @@ -84,6 +85,7 @@ export class ColorManager { public setTheme(theme: ITheme): void { if (theme.foreground) this.colors.foreground = theme.foreground; if (theme.background) this.colors.background = theme.background; + if (theme.cursor) this.colors.cursor = theme.cursor; if (theme.black) this.colors.ansi[0] = theme.black; if (theme.red) this.colors.ansi[1] = theme.red; if (theme.green) this.colors.ansi[2] = theme.green; diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index 941d6d3b..10f3ad8c 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -139,21 +139,29 @@ export class CursorRenderLayer extends BaseRenderLayer { } private _renderBarCursor(terminal: ITerminal, x: number, y: number, charData: CharData): void { + this._ctx.save(); + this._ctx.fillStyle = this.colors.cursor; this.drawLeftLineAtCell(x, y); + this._ctx.restore(); } private _renderBlockCursor(terminal: ITerminal, x: number, y: number, charData: CharData): void { + this._ctx.save(); + this._ctx.fillStyle = this.colors.cursor; this.fillCells(x, y, 1, 1); - this.drawChar(terminal, charData[CHAR_DATA_CHAR_INDEX], charData[CHAR_DATA_CODE_INDEX], x, y, COLOR_CODES.BLACK); + this._ctx.restore(); + this.drawCharTrueColor(terminal, charData[CHAR_DATA_CHAR_INDEX], charData[CHAR_DATA_CODE_INDEX], x, y, this.colors.background); } private _renderUnderlineCursor(terminal: ITerminal, x: number, y: number, charData: CharData): void { + this._ctx.save(); + this._ctx.fillStyle = this.colors.cursor; this.drawBottomLineAtCell(x, y); + this._ctx.restore(); } private _renderBlurCursor(terminal: ITerminal, x: number, y: number, charData: CharData): void { - // TODO: Support cursor colors - this.drawSquareAtCell(x, y, this.colors.foreground); + this.drawSquareAtCell(x, y, this.colors.cursor); } } diff --git a/src/renderer/Interfaces.ts b/src/renderer/Interfaces.ts index b47a75b9..fd94d59d 100644 --- a/src/renderer/Interfaces.ts +++ b/src/renderer/Interfaces.ts @@ -52,5 +52,6 @@ export interface IRenderLayer { export interface IColorSet { foreground: string; background: string; + cursor: string; ansi: string[]; } diff --git a/src/utils/TestUtils.test.ts b/src/utils/TestUtils.test.ts index 3a66d49d..f4eae64d 100644 --- a/src/utils/TestUtils.test.ts +++ b/src/utils/TestUtils.test.ts @@ -7,6 +7,7 @@ import { LineData } from '../Types'; import * as Browser from './Browser'; export class MockTerminal implements ITerminal { + isFocused: boolean; options: ITerminalOptions = {}; element: HTMLElement; rowContainer: HTMLElement;