diff --git a/addons/xterm-addon-canvas/src/CanvasRenderer.ts b/addons/xterm-addon-canvas/src/CanvasRenderer.ts index c0c332ef..cb30106d 100644 --- a/addons/xterm-addon-canvas/src/CanvasRenderer.ts +++ b/addons/xterm-addon-canvas/src/CanvasRenderer.ts @@ -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) ]; diff --git a/addons/xterm-addon-canvas/src/CursorRenderLayer.ts b/addons/xterm-addon-canvas/src/CursorRenderLayer.ts index 4d7e0570..19d414b6 100644 --- a/addons/xterm-addon-canvas/src/CursorRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/CursorRenderLayer.ts @@ -36,7 +36,7 @@ export class CursorRenderLayer extends BaseRenderLayer { zIndex: number, colors: IColorSet, rendererId: number, - private _onRequestRedraw: IEventEmitter, + private readonly _onRequestRedraw: IEventEmitter, bufferService: IBufferService, optionsService: IOptionsService, private readonly _coreService: ICoreService, diff --git a/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts b/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts index 3b25ec8f..61fc4783 100644 --- a/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts @@ -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]; diff --git a/addons/xterm-addon-canvas/src/TextRenderLayer.ts b/addons/xterm-addon-canvas/src/TextRenderLayer.ts index d2179e0f..0308f125 100644 --- a/addons/xterm-addon-canvas/src/TextRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/TextRenderLayer.ts @@ -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; diff --git a/addons/xterm-addon-canvas/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-canvas/src/atlas/CharAtlasUtils.ts index 4c84c86a..5d44b859 100644 --- a/addons/xterm-addon-canvas/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-canvas/src/atlas/CharAtlasUtils.ts @@ -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 { diff --git a/addons/xterm-addon-canvas/src/atlas/DynamicCharAtlas.ts b/addons/xterm-addon-canvas/src/atlas/DynamicCharAtlas.ts index f5fc2c99..3098538d 100644 --- a/addons/xterm-addon-canvas/src/atlas/DynamicCharAtlas.ts +++ b/addons/xterm-addon-canvas/src/atlas/DynamicCharAtlas.ts @@ -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); diff --git a/addons/xterm-addon-ligatures/README.md b/addons/xterm-addon-ligatures/README.md index 8f869d73..fad2a7ef 100644 --- a/addons/xterm-addon-ligatures/README.md +++ b/addons/xterm-addon-ligatures/README.md @@ -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/ diff --git a/addons/xterm-addon-ligatures/src/LigaturesAddon.ts b/addons/xterm-addon-ligatures/src/LigaturesAddon.ts index c19bf2f8..c4586b38 100644 --- a/addons/xterm-addon-ligatures/src/LigaturesAddon.ts +++ b/addons/xterm-addon-ligatures/src/LigaturesAddon.ts @@ -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) { + this._fallbackLigatures = (options?.fallbackLigatures || [ + '<--', '<---', '<<-', '<-', '->', '->>', '-->', '--->', + '<==', '<===', '<<=', '<=', '=>', '=>>', '==>', '===>', '>=', '>>=', + '<->', '<-->', '<--->', '<---->', '<=>', '<==>', '<===>', '<====>', '-------->', + '<~~', '<~', '~>', '~~>', '::', ':::', '==', '!=', '===', '!==', + ':=', ':-', ':+', '<*', '<*>', '*>', '<|', '<|>', '|>', '+:', '-:', '=:', ':>', + '++', '+++', ' ---> + * <== <=== <<= <= => =>> ==> ===> >= >>= + * <-> <--> <---> <----> <=> <==> <===> <====> --------> + * <~~ <~ ~> ~~> :: ::: == != === !== + * := :- :+ <* <*> *> <| <|> |> +: -: =: :> + * ++ +++