Merge branch 'master' into underline

This commit is contained in:
Daniel Imms
2022-07-30 06:40:41 -07:00
committed by GitHub
29 changed files with 267 additions and 101 deletions
@@ -12,7 +12,7 @@ import { LinkRenderLayer } from './LinkRenderLayer';
import { Disposable } from 'common/Lifecycle';
import { IColorSet, ILinkifier2 } from 'browser/Types';
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService } from 'browser/services/Services';
import { IBufferService, IOptionsService, IInstantiationService, IDecorationService, ICoreService } from 'common/services/Services';
import { IBufferService, IOptionsService, IDecorationService, ICoreService } from 'common/services/Services';
import { removeTerminalFromCache } from './atlas/CharAtlasCache';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { observeDevicePixelDimensions } from 'browser/renderer/DevicePixelObserver';
@@ -46,7 +46,7 @@ export class CanvasRenderer extends Disposable implements IRenderer {
const allowTransparency = this._optionsService.rawOptions.allowTransparency;
this._renderLayers = [
new TextRenderLayer(this._screenElement, 0, this._colors, allowTransparency, this._id, this._bufferService, this._optionsService, characterJoinerService, decorationService),
new SelectionRenderLayer(this._screenElement, 1, this._colors, this._id, this._bufferService, this._optionsService, decorationService),
new SelectionRenderLayer(this._screenElement, 1, this._colors, this._id, this._bufferService, coreBrowserService, decorationService, this._optionsService),
new LinkRenderLayer(this._screenElement, 2, this._colors, this._id, linkifier2, this._bufferService, this._optionsService, decorationService),
new CursorRenderLayer(this._screenElement, 3, this._colors, this._id, this._onRequestRedraw, this._bufferService, this._optionsService, coreService, coreBrowserService, decorationService)
];
@@ -36,7 +36,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
zIndex: number,
colors: IColorSet,
rendererId: number,
private _onRequestRedraw: IEventEmitter<IRequestRedrawEvent>,
private readonly _onRequestRedraw: IEventEmitter<IRequestRedrawEvent>,
bufferService: IBufferService,
optionsService: IOptionsService,
private readonly _coreService: ICoreService,
@@ -3,10 +3,12 @@
* @license MIT
*/
import { IRenderDimensions } from 'browser/renderer/Types';
import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { IColorSet } from 'browser/Types';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { ICoreBrowserService } from 'browser/services/Services';
import { IEventEmitter } from 'common/EventEmitter';
interface ISelectionState {
start?: [number, number];
@@ -24,8 +26,9 @@ export class SelectionRenderLayer extends BaseRenderLayer {
colors: IColorSet,
rendererId: number,
bufferService: IBufferService,
optionsService: IOptionsService,
decorationService: IDecorationService
private readonly _coreBrowserService: ICoreBrowserService,
decorationService: IDecorationService,
optionsService: IOptionsService
) {
super(container, 'selection', zIndex, true, colors, rendererId, bufferService, optionsService, decorationService);
this._clearState();
@@ -45,7 +48,7 @@ export class SelectionRenderLayer extends BaseRenderLayer {
// On resize use the base render layer's cached selection values since resize clears _state
// inside reset.
if (this._selectionStart && this._selectionEnd) {
this.onSelectionChanged(this._selectionStart, this._selectionEnd, this._columnSelectMode);
this._redrawSelection(this._selectionStart, this._selectionEnd, this._columnSelectMode);
}
}
@@ -56,9 +59,22 @@ export class SelectionRenderLayer extends BaseRenderLayer {
}
}
public onBlur(): void {
this.reset();
this._redrawSelection(this._selectionStart, this._selectionEnd, this._columnSelectMode);
}
public onFocus(): void {
this.reset();
this._redrawSelection(this._selectionStart, this._selectionEnd, this._columnSelectMode);
}
public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
super.onSelectionChanged(start, end, columnSelectMode);
this._redrawSelection(start, end, columnSelectMode);
}
private _redrawSelection(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
// Selection has not changed
if (!this._didStateChange(start, end, columnSelectMode, this._bufferService.buffer.ydisp)) {
return;
@@ -85,7 +101,9 @@ export class SelectionRenderLayer extends BaseRenderLayer {
return;
}
this._ctx.fillStyle = this._colors.selectionTransparent.css;
this._ctx.fillStyle = (this._coreBrowserService.isFocused
? this._colors.selectionBackgroundTransparent
: this._colors.selectionInactiveBackgroundTransparent).css;
if (columnSelectMode) {
const startCol = start[0];
@@ -14,6 +14,7 @@ import { CellData } from 'common/buffer/CellData';
import { IOptionsService, IBufferService, IDecorationService } from 'common/services/Services';
import { ICharacterJoinerService } from 'browser/services/Services';
import { JoinedCellData } from 'browser/services/CharacterJoinerService';
import { color, css } from 'common/Color';
/**
* This CharData looks like a null character, which will forc a clear and render
@@ -177,6 +178,12 @@ export class TextRenderLayer extends BaseRenderLayer {
nextFillStyle = this._colors.ansi[cell.getBgColor()].css;
}
// Apply dim to the background, this is relatively slow as the CSS is re-parsed but dim is
// rarely used
if (nextFillStyle && cell.isDim()) {
nextFillStyle = color.multiplyOpacity(css.toColor(nextFillStyle), 0.5).css;
}
// Get any decoration foreground/background overrides, this must be fetched before the early
// exist but applied after inverse
let isTop = false;
@@ -15,7 +15,7 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number
background: colors.background,
cursor: undefined,
cursorAccent: undefined,
selection: undefined,
selectionBackground: undefined,
ansi: colors.ansi.slice()
};
return {
@@ -225,13 +225,18 @@ export class DynamicCharAtlas extends BaseCharAtlas {
// around the anti-aliased edges of the glyph, and it would look too dark.
return TRANSPARENT_COLOR;
}
let result: IColor;
if (glyph.bg === INVERTED_DEFAULT_COLOR) {
return this._config.colors.foreground;
result = this._config.colors.foreground;
} else if (glyph.bg < 256) {
result = this._getColorFromAnsiIndex(glyph.bg);
} else {
result = this._config.colors.background;
}
if (glyph.bg < 256) {
return this._getColorFromAnsiIndex(glyph.bg);
if (glyph.dim) {
result = color.blend(this._config.colors.background, color.multiplyOpacity(result, 0.5));
}
return this._config.colors.background;
return result;
}
private _getForegroundColor(glyph: IGlyphIdentifier): IColor {
@@ -274,6 +279,7 @@ export class DynamicCharAtlas extends BaseCharAtlas {
if (glyph.dim) {
this._tmpCtx.globalAlpha = DIM_OPACITY;
}
// Draw the character
this._tmpCtx.fillText(glyph.chars, 0, this._config.scaledCharHeight);
+6 -5
View File
@@ -33,15 +33,16 @@ This package locates the font file on disk for the font currently in use by the
Since this package depends on being able to find and resolve a system font from disk, it has to have system access that isn't available in the web browser. As a result, this package is mainly useful in environments that combine browser and Node.js runtimes (such as [Electron]).
### Fallback Ligatures
When ligatures cannot be fetched from the environment, a set of "fallback" ligatures is used to get the most common ligatures working. These fallback ligatures can be customized with options passed to `LigatureAddon.constructor`.
### Fonts
This package makes use of the following fonts for testing:
* [Fira Code][Fira Code] - [Licensed under the OFL][Fira Code License] by Nikita
Prokopov, Mozilla Foundation with reserved names Fira Code, Fira Mono, and
Fira Sans
* [Iosevka] - [Licensed under the OFL][Iosevka License] by Belleve Invis with
reserved name Iosevka
* [Fira Code][Fira Code] - [Licensed under the OFL][Fira Code License] by Nikita Prokopov, Mozilla Foundation with reserved names Fira Code, Fira Mono, and Fira Sans
* [Iosevka] - [Licensed under the OFL][Iosevka License] by Belleve Invis with reserved name Iosevka
[xterm.js]: https://github.com/xtermjs/xterm.js
[Electron]: https://electronjs.org/
@@ -5,6 +5,7 @@
import { Terminal } from 'xterm';
import { enableLigatures } from '.';
import { ILigatureOptions } from './Types';
export interface ITerminalAddon {
activate(terminal: Terminal): void;
@@ -12,12 +13,31 @@ export interface ITerminalAddon {
}
export class LigaturesAddon implements ITerminalAddon {
constructor() {}
private readonly _fallbackLigatures: string[];
public activate(terminal: Terminal): void {
enableLigatures(terminal);
private _terminal: Terminal | undefined;
private _characterJoinerId: number | undefined;
constructor(options?: Partial<ILigatureOptions>) {
this._fallbackLigatures = (options?.fallbackLigatures || [
'<--', '<---', '<<-', '<-', '->', '->>', '-->', '--->',
'<==', '<===', '<<=', '<=', '=>', '=>>', '==>', '===>', '>=', '>>=',
'<->', '<-->', '<--->', '<---->', '<=>', '<==>', '<===>', '<====>', '-------->',
'<~~', '<~', '~>', '~~>', '::', ':::', '==', '!=', '===', '!==',
':=', ':-', ':+', '<*', '<*>', '*>', '<|', '<|>', '|>', '+:', '-:', '=:', ':>',
'++', '+++', '<!--', '<!---', '<***>'
]).sort((a, b) => b.length - a.length);
}
public dispose(): void {}
}
public activate(terminal: Terminal): void {
this._terminal = terminal;
this._characterJoinerId = enableLigatures(terminal, this._fallbackLigatures);
}
public dispose(): void {
if (this._characterJoinerId !== undefined) {
this._terminal?.deregisterCharacterJoiner(this._characterJoinerId);
this._characterJoinerId = undefined;
}
}
}
+8
View File
@@ -0,0 +1,8 @@
/**
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
* @license MIT
*/
export interface ILigatureOptions {
fallbackLigatures: string[];
}
@@ -144,7 +144,6 @@ describe('xterm-addon-ligatures', () => {
assert.deepEqual(term.joiner!(input), []);
await delay(500);
assert.isTrue(onRefresh.notCalled);
assert.throws(() => term.joiner!(input));
});
it('returns nothing if the font is not present on the system', async () => {
@@ -176,7 +175,6 @@ describe('xterm-addon-ligatures', () => {
assert.deepEqual(term.joiner!(input), []);
await delay(500);
assert.isTrue(onRefresh.notCalled);
assert.throws(() => term.joiner!(input));
});
it('ensures no empty errors are thrown', async () => {
@@ -185,7 +183,6 @@ describe('xterm-addon-ligatures', () => {
assert.deepEqual(term.joiner!(input), []);
await delay(500);
assert.isTrue(onRefresh.notCalled);
assert.throws(() => term.joiner!(input), 'Failure while loading font');
(fontLigatures.loadFile as sinon.SinonStub).restore();
});
});
+20 -6
View File
@@ -26,13 +26,13 @@ const CACHE_SIZE = 100000;
* start to render them.
* @param term Terminal instance from xterm.js
*/
export function enableLigatures(term: Terminal): void {
export function enableLigatures(term: Terminal, fallbackLigatures: string[] = []): number {
let currentFontName: string | undefined = undefined;
let font: Font | undefined = undefined;
let loadingState: LoadingState = LoadingState.UNLOADED;
let loadError: any | undefined = undefined;
term.registerCharacterJoiner((text: string): [number, number][] => {
return term.registerCharacterJoiner((text: string): [number, number][] => {
// If the font hasn't been loaded yet, load it and return an empty result
const termFont = term.options.fontFamily;
if (
@@ -63,6 +63,9 @@ export function enableLigatures(term: Terminal): void {
// sure our font is still vaild.
if (currentCallFontName === term.options.fontFamily) {
loadingState = LoadingState.FAILED;
if (term.options.logLevel === 'debug') {
console.debug(loadError, new Error('Failure while loading font'));
}
font = undefined;
loadError = e;
}
@@ -76,10 +79,21 @@ export function enableLigatures(term: Terminal): void {
range => [range[0], range[1]]
);
}
if (loadingState === LoadingState.FAILED) {
throw loadError || new Error('Failure while loading font');
}
return [];
return getFallbackRanges(text, fallbackLigatures);
});
}
function getFallbackRanges(text: string, fallbackLigatures: string[]): [number, number][] {
const ranges: [number, number][] = [];
for (let i = 0; i < text.length; i++) {
for (let j = 0; j < fallbackLigatures.length; j++) {
if (text.startsWith(fallbackLigatures[j], i)) {
ranges.push([i, i + fallbackLigatures[j].length]);
i += fallbackLigatures[j].length - 1;
break;
}
}
}
return ranges;
}
@@ -17,11 +17,14 @@ declare module 'xterm-addon-ligatures' {
export class LigaturesAddon implements ITerminalAddon {
/**
* Creates a new ligatures addon.
*
* @param options Options for the ligatures addon.
*/
constructor();
constructor(options?: Partial<ILigatureOptions>);
/**
* Activates the addon
*
* @param terminal The terminal the addon is being loaded in.
*/
public activate(terminal: Terminal): void;
@@ -31,4 +34,25 @@ declare module 'xterm-addon-ligatures' {
*/
public dispose(): void;
}
/**
* Options for the ligatures addon.
*/
export interface ILigatureOptions {
/**
* Fallback ligatures to use when the font access API is either not supported by the browser or
* access is denied. The default set of ligatures is taken from Iosevka's default "calt"
* ligation set: https://typeof.net/Iosevka/
*
* ```
* <-- <--- <<- <- -> ->> --> --->
* <== <=== <<= <= => =>> ==> ===> >= >>=
* <-> <--> <---> <----> <=> <==> <===> <====> -------->
* <~~ <~ ~> ~~> :: ::: == != === !==
* := :- :+ <* <*> *> <| <|> |> +: -: =: :>
* ++ +++ <!-- <!--- <***>
* ```
*/
fallbackLigatures: string[]
}
}
@@ -5,7 +5,7 @@
import { createProgram, expandFloat32Array, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils';
import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext } from './Types';
import { Attributes, FgFlags } from 'common/buffer/Constants';
import { Attributes, BgFlags, FgFlags } from 'common/buffer/Constants';
import { Terminal } from 'xterm';
import { IColor } from 'common/Types';
import { IColorSet } from 'browser/Types';
@@ -244,8 +244,9 @@ export class RectangleRenderer extends Disposable {
const r = ((rgba >> 24) & 0xFF) / 255;
const g = ((rgba >> 16) & 0xFF) / 255;
const b = ((rgba >> 8 ) & 0xFF) / 255;
const a = bg & BgFlags.DIM ? 0.5 : 1;
this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, 1);
this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, a);
}
private _addRectangle(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, r: number, g: number, b: number, a: number): void {
+5 -3
View File
@@ -5,11 +5,11 @@
import { Terminal, ITerminalAddon, IEvent } from 'xterm';
import { WebglRenderer } from './WebglRenderer';
import { ICharacterJoinerService, IRenderService } from 'browser/services/Services';
import { ICharacterJoinerService, ICoreBrowserService, IRenderService } from 'browser/services/Services';
import { IColorSet } from 'browser/Types';
import { EventEmitter } from 'common/EventEmitter';
import { isSafari } from 'common/Platform';
import { IDecorationService } from 'common/services/Services';
import { ICoreService, IDecorationService } from 'common/services/Services';
export class WebglAddon implements ITerminalAddon {
private _terminal?: Terminal;
@@ -31,9 +31,11 @@ export class WebglAddon implements ITerminalAddon {
this._terminal = terminal;
const renderService: IRenderService = (terminal as any)._core._renderService;
const characterJoinerService: ICharacterJoinerService = (terminal as any)._core._characterJoinerService;
const coreBrowserService: ICoreBrowserService = (terminal as any)._core._coreBrowserService;
const coreService: ICoreService = (terminal as any)._core.coreService;
const decorationService: IDecorationService = (terminal as any)._core._decorationService;
const colors: IColorSet = (terminal as any)._core._colorManager.colors;
this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, decorationService, this._preserveDrawingBuffer);
this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, coreBrowserService, coreService, decorationService, this._preserveDrawingBuffer);
this._renderer.onContextLoss(() => this._onContextLoss.fire());
renderService.setRenderer(this._renderer);
}
+11 -4
View File
@@ -21,10 +21,11 @@ import { ITerminal, IColorSet } from 'browser/Types';
import { EventEmitter } from 'common/EventEmitter';
import { CellData } from 'common/buffer/CellData';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { ICharacterJoinerService } from 'browser/services/Services';
import { ICharacterJoinerService, ICoreBrowserService } from 'browser/services/Services';
import { CharData, ICellData } from 'common/Types';
import { AttributeData } from 'common/buffer/AttributeData';
import { IDecorationService } from 'common/services/Services';
import { ICoreService, IDecorationService } from 'common/services/Services';
import { color, rgba as rgbaNs } from 'common/Color';
export class WebglRenderer extends Disposable implements IRenderer {
private _renderLayers: IRenderLayer[];
@@ -55,6 +56,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
private _terminal: Terminal,
private _colors: IColorSet,
private readonly _characterJoinerService: ICharacterJoinerService,
private readonly _coreBrowserService: ICoreBrowserService,
coreService: ICoreService,
private readonly _decorationService: IDecorationService,
preserveDrawingBuffer?: boolean
) {
@@ -64,7 +67,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._renderLayers = [
new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core),
new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._core, this._onRequestRedraw)
new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._onRequestRedraw, this._coreBrowserService, coreService)
];
this.dimensions = {
scaledCharWidth: 0,
@@ -187,12 +190,16 @@ export class WebglRenderer extends Disposable implements IRenderer {
for (const l of this._renderLayers) {
l.onBlur(this._terminal);
}
// Request a redraw for active/inactive selection background
this._requestRedrawViewport();
}
public onFocus(): void {
for (const l of this._renderLayers) {
l.onFocus(this._terminal);
}
// Request a redraw for active/inactive selection background
this._requestRedrawViewport();
}
public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
@@ -408,7 +415,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
// Apply the selection color if needed
if (this._isCellSelected(x, y)) {
bgOverride = this._colors.selectionOpaque.rgba >> 8 & 0xFFFFFF;
bgOverride = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF;
if (this._colors.selectionForeground) {
fgOverride = this._colors.selectionForeground.rgba >> 8 & 0xFFFFFF;
}
@@ -21,9 +21,11 @@ export function generateConfig(scaledCellWidth: number, scaledCellHeight: number
background: colors.background,
cursor: NULL_COLOR,
cursorAccent: NULL_COLOR,
selectionTransparent: NULL_COLOR,
selectionOpaque: NULL_COLOR,
selectionForeground: NULL_COLOR,
selectionBackgroundTransparent: NULL_COLOR,
selectionBackgroundOpaque: NULL_COLOR,
selectionInactiveBackgroundTransparent: NULL_COLOR,
selectionInactiveBackgroundOpaque: NULL_COLOR,
// For the static char atlas, we only use the first 16 colors, but we need all 256 for the
// dynamic character atlas.
ansi: colors.ansi.slice(),
@@ -193,7 +193,7 @@ export class WebglCharAtlas implements IDisposable {
return this._config.colors.ansi[idx];
}
private _getBackgroundColor(bgColorMode: number, bgColor: number, inverse: boolean): IColor {
private _getBackgroundColor(bgColorMode: number, bgColor: number, inverse: boolean, dim: boolean): IColor {
if (this._config.allowTransparency) {
// The background color might have some transparency, so we need to render it as fully
// transparent in the atlas. Otherwise we'd end up drawing the transparent background twice
@@ -201,50 +201,76 @@ export class WebglCharAtlas implements IDisposable {
return TRANSPARENT_COLOR;
}
let result: IColor;
switch (bgColorMode) {
case Attributes.CM_P16:
case Attributes.CM_P256:
return this._getColorFromAnsiIndex(bgColor);
result = this._getColorFromAnsiIndex(bgColor);
break;
case Attributes.CM_RGB:
const arr = AttributeData.toColorRGB(bgColor);
// TODO: This object creation is slow
return {
rgba: bgColor << 8,
css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}`
};
result = rgba.toColor(arr[0], arr[1], arr[2]);
break;
case Attributes.CM_DEFAULT:
default:
if (inverse) {
return this._config.colors.foreground;
result = this._config.colors.foreground;
} else {
result = this._config.colors.background;
}
return this._config.colors.background;
break;
}
if (dim) {
// Blend here instead of using opacity because transparent colors mess with clipping the
// glyph's bounding box
result = color.blend(this._config.colors.background, color.multiplyOpacity(result, 0.5));
}
return result;
}
private _getForegroundColor(bg: number, bgColorMode: number, bgColor: number, fg: number, fgColorMode: number, fgColor: number, inverse: boolean, bold: boolean, excludeFromContrastRatioDemands: boolean): IColor {
const minimumContrastColor = this._getMinimumContrastColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, bold, excludeFromContrastRatioDemands);
private _getForegroundColor(bg: number, bgColorMode: number, bgColor: number, fg: number, fgColorMode: number, fgColor: number, inverse: boolean, dim: boolean, bold: boolean, excludeFromContrastRatioDemands: boolean): IColor {
// TODO: Pass dim along to get min contrast?
const minimumContrastColor = this._getMinimumContrastColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, false, bold, excludeFromContrastRatioDemands);
if (minimumContrastColor) {
return minimumContrastColor;
}
let result: IColor;
switch (fgColorMode) {
case Attributes.CM_P16:
case Attributes.CM_P256:
if (this._config.drawBoldTextInBrightColors && bold && fgColor < 8) {
fgColor += 8;
}
return this._getColorFromAnsiIndex(fgColor);
result = this._getColorFromAnsiIndex(fgColor);
break;
case Attributes.CM_RGB:
const arr = AttributeData.toColorRGB(fgColor);
return rgba.toColor(arr[0], arr[1], arr[2]);
result = rgba.toColor(arr[0], arr[1], arr[2]);
break;
case Attributes.CM_DEFAULT:
default:
if (inverse) {
// Inverse should always been opaque, even when transparency is used
return color.opaque(this._config.colors.background);
result = this._config.colors.background;
} else {
result = this._config.colors.foreground;
}
return this._config.colors.foreground;
}
// Always use an opaque color regardless of allowTransparency
if (this._config.allowTransparency) {
result = color.opaque(result);
}
// Apply dim to the color, opacity is fine to use for the foreground color
if (dim) {
result = color.multiplyOpacity(result, 0.5);
}
return result;
}
private _resolveBackgroundRgba(bgColorMode: number, bgColor: number, inverse: boolean): number {
@@ -360,7 +386,7 @@ export class WebglCharAtlas implements IDisposable {
}
// draw the background
const backgroundColor = this._getBackgroundColor(bgColorMode, bgColor, inverse);
const backgroundColor = this._getBackgroundColor(bgColorMode, bgColor, inverse, dim);
// Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, regardless of
// transparency in backgroundColor
this._tmpCtx.globalCompositeOperation = 'copy';
@@ -376,14 +402,9 @@ export class WebglCharAtlas implements IDisposable {
this._tmpCtx.textBaseline = TEXT_BASELINE;
const powerLineGlyph = chars.length === 1 && isPowerlineGlyph(chars.charCodeAt(0));
const foregroundColor = this._getForegroundColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, bold, excludeFromContrastRatioDemands(chars.charCodeAt(0)));
const foregroundColor = this._getForegroundColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, dim, bold, excludeFromContrastRatioDemands(chars.charCodeAt(0)));
this._tmpCtx.fillStyle = foregroundColor.css;
// Apply alpha to dim the character
if (dim) {
this._tmpCtx.globalAlpha = DIM_OPACITY;
}
// For powerline glyphs left/top padding is excluded (https://github.com/microsoft/vscode/issues/120129)
const padding = powerLineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING * 2;
@@ -10,6 +10,8 @@ import { CellData } from 'common/buffer/CellData';
import { IColorSet, ITerminal } from 'browser/Types';
import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types';
import { IEventEmitter } from 'common/EventEmitter';
import { ICoreBrowserService } from 'browser/services/Services';
import { ICoreService } from 'common/services/Services';
interface ICursorState {
x: number;
@@ -35,8 +37,9 @@ export class CursorRenderLayer extends BaseRenderLayer {
container: HTMLElement,
zIndex: number,
colors: IColorSet,
private readonly _terminal: ITerminal,
private _onRequestRefreshRowsEvent: IEventEmitter<IRequestRedrawEvent>
private _onRequestRefreshRowsEvent: IEventEmitter<IRequestRedrawEvent>,
private readonly _coreBrowserService: ICoreBrowserService,
private readonly _coreService: ICoreService
) {
super(container, 'cursor', zIndex, true, colors);
this._state = {
@@ -91,9 +94,9 @@ export class CursorRenderLayer extends BaseRenderLayer {
public onOptionsChanged(terminal: Terminal): void {
if (terminal.options.cursorBlink) {
if (!this._cursorBlinkStateManager) {
this._cursorBlinkStateManager = new CursorBlinkStateManager(terminal, () => {
this._cursorBlinkStateManager = new CursorBlinkStateManager(() => {
this._render(terminal, true);
});
}, this._coreBrowserService);
}
} else {
this._cursorBlinkStateManager?.dispose();
@@ -118,8 +121,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
private _render(terminal: Terminal, triggeredByAnimationFrame: boolean): void {
// Don't draw the cursor if it's hidden
// TODO: Need to expose API for this
if (!this._terminal.coreService.isCursorInitialized || this._terminal.coreService.isCursorHidden) {
if (!this._coreService.isCursorInitialized || this._coreService.isCursorHidden) {
this._clearCursor();
return;
}
@@ -142,7 +144,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
return;
}
if (!isTerminalFocused(terminal)) {
if (!this._coreBrowserService.isFocused) {
this._clearCursor();
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
@@ -171,7 +173,7 @@ export class CursorRenderLayer extends BaseRenderLayer {
// The cursor is already in the correct spot, don't redraw
if (this._state.x === cursorX &&
this._state.y === viewportRelativeCursorY &&
this._state.isFocused === isTerminalFocused(terminal) &&
this._state.isFocused === this._coreBrowserService.isFocused &&
this._state.style === terminal.options.cursorStyle &&
this._state.width === this._cell.getWidth()) {
return;
@@ -254,11 +256,11 @@ class CursorBlinkStateManager {
private _animationTimeRestarted: number | undefined;
constructor(
terminal: Terminal,
private _renderCallback: () => void
private _renderCallback: () => void,
coreBrowserService: ICoreBrowserService
) {
this.isCursorVisible = true;
if (isTerminalFocused(terminal)) {
if (coreBrowserService.isFocused) {
this._restartInterval();
}
}
@@ -373,7 +375,3 @@ class CursorBlinkStateManager {
this.restartBlinkAnimation(terminal);
}
}
function isTerminalFocused(terminal: Terminal): boolean {
return document.activeElement === terminal.textarea && document.hasFocus();
}
@@ -832,7 +832,7 @@ describe('WebGL Renderer Integration Tests', async () => {
});
});
describe('selection', async () => {
describe('selectionBackground', async () => {
if (areTestsEnabled) {
before(async () => setupBrowser());
after(async () => browser.close());
@@ -843,7 +843,7 @@ describe('WebGL Renderer Integration Tests', async () => {
const theme: ITheme = {
foreground: '#FF0000',
background: '#00FF00',
selection: '#0000FF'
selectionBackground: '#0000FF'
};
await page.evaluate(`window.term.options.theme = ${JSON.stringify(theme)};`);
await writeSync(page, `\\x1b[7m█\\x1b[0m`);
+1 -1
View File
@@ -106,7 +106,7 @@ const paddingElement = <HTMLInputElement>document.getElementById('padding');
const xtermjsTheme = {
foreground: '#F8F8F8',
background: '#2D2E2C',
selection: '#5DA5D533',
selectionBackground: '#5DA5D533',
black: '#1E1E1D',
brightBlack: '#262625',
red: '#CE5C5C',

Some files were not shown because too many files have changed in this diff Show More