Initial bg/fg renderer decoration proof of concept

Part of #3770
This commit is contained in:
Daniel Imms
2022-05-09 12:44:51 -07:00
parent 85e0625078
commit 63eb9a4555
8 changed files with 115 additions and 15 deletions
+12 -1
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IDirtyRowService, ICoreMouseService, ICharsetService, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum } from 'common/services/Services';
import { IBufferService, ICoreService, ILogService, IOptionsService, ITerminalOptions, IDirtyRowService, ICoreMouseService, ICharsetService, IUnicodeService, IUnicodeVersionProvider, LogLevelEnum, IDecorationService, IInternalDecoration } from 'common/services/Services';
import { IEvent, EventEmitter } from 'common/EventEmitter';
import { clone } from 'common/Clone';
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
@@ -11,6 +11,7 @@ import { IBufferSet, IBuffer } from 'common/buffer/Types';
import { BufferSet } from 'common/buffer/BufferSet';
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEventType, ICharset, IModes, IAttributeData } from 'common/Types';
import { UnicodeV6 } from 'common/input/UnicodeV6';
import { IDecorationOptions, IDecoration } from 'xterm';
export class MockBufferService implements IBufferService {
public serviceBrand: any;
@@ -158,3 +159,13 @@ export class MockUnicodeService implements IUnicodeService {
throw new Error('Method not implemented.');
}
}
export class MockDecorationService implements IDecorationService {
public serviceBrand: any;
public get decorations(): IterableIterator<IInternalDecoration> { return [].values(); };
public onDecorationRegistered = new EventEmitter<IInternalDecoration>().event;
public onDecorationRemoved = new EventEmitter<IInternalDecoration>().event;
public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined { return undefined; }
public *getDecorationsOnLine(line: number): IterableIterator<IInternalDecoration> { }
public dispose(): void { }
}
+45
View File
@@ -6,6 +6,7 @@
import { EventEmitter } from 'common/EventEmitter';
import { Disposable } from 'common/Lifecycle';
import { IDecorationService, IInternalDecoration } from 'common/services/Services';
import { IColorRGB } from 'common/Types';
import { IDecorationOptions, IDecoration, IMarker, IEvent } from 'xterm';
export class DecorationService extends Disposable implements IDecorationService {
@@ -45,6 +46,15 @@ export class DecorationService extends Disposable implements IDecorationService
return decoration;
}
public *getDecorationsOnLine(line: number): IterableIterator<IInternalDecoration> {
// TODO: This could be made much faster if _decorations was sorted by line (and col?)
for (const d of this.decorations) {
if (d.marker.line === line) {
yield d;
}
}
}
public dispose(): void {
for (const decoration of this._decorations) {
this._onDecorationRemoved.fire(decoration);
@@ -64,6 +74,32 @@ class Decoration extends Disposable implements IInternalDecoration {
private _onDispose = this.register(new EventEmitter<void>());
public readonly onDispose = this._onDispose.event;
// TODO: React to changes on options
private _cachedBg: IColorRGB | undefined | null = null;
public get backgroundColorRGB(): IColorRGB | undefined {
if (this._cachedBg === null) {
if (this.options.backgroundColor) {
this._cachedBg = toColorRGB(this.options.backgroundColor);
} else {
this._cachedBg = undefined;
}
}
return this._cachedBg;
}
// TODO: React to changes on options
private _cachedFg: IColorRGB | undefined | null = null;
public get foregroundColorRGB(): IColorRGB | undefined {
if (this._cachedFg === null) {
if (this.options.foregroundColor) {
this._cachedFg = toColorRGB(this.options.foregroundColor);
} else {
this._cachedFg = undefined;
}
}
return this._cachedFg;
}
constructor(
public readonly options: IDecorationOptions
) {
@@ -73,6 +109,7 @@ class Decoration extends Disposable implements IInternalDecoration {
this.options.overviewRulerOptions.position = 'full';
}
}
public override dispose(): void {
if (this._isDisposed) {
return;
@@ -82,3 +119,11 @@ class Decoration extends Disposable implements IInternalDecoration {
super.dispose();
}
}
function toColorRGB(css: string): IColorRGB {
// #rrggbb
if (css.length === 7) {
return [parseInt(css.slice(1, 3), 16), parseInt(css.slice(3, 5), 16), parseInt(css.slice(5, 7), 16)];
}
throw new Error('css.toColor: Unsupported css format');
}
+5 -1
View File
@@ -5,7 +5,7 @@
import { IEvent, IEventEmitter } from 'common/EventEmitter';
import { IBuffer, IBufferSet } from 'common/buffer/Types';
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharset, IWindowOptions, IModes, IAttributeData, ScrollSource, IDisposable } from 'common/Types';
import { IDecPrivateModes, ICoreMouseEvent, CoreMouseEncoding, ICoreMouseProtocol, CoreMouseEventType, ICharset, IWindowOptions, IModes, IAttributeData, ScrollSource, IDisposable, IColorRGB } from 'common/Types';
import { createDecorator } from 'common/services/ServiceRegistry';
import { IDecorationOptions, IDecoration } from 'xterm';
@@ -308,8 +308,12 @@ export interface IDecorationService extends IDisposable {
readonly onDecorationRegistered: IEvent<IInternalDecoration>;
readonly onDecorationRemoved: IEvent<IInternalDecoration>;
registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined;
/** Iterates over the decorations on a line (in no particular order). */
getDecorationsOnLine(line: number): IterableIterator<IInternalDecoration>;
}
export interface IInternalDecoration extends IDecoration {
readonly options: IDecorationOptions;
readonly backgroundColorRGB: IColorRGB | undefined;
readonly foregroundColorRGB: IColorRGB | undefined;
readonly onRenderEmitter: IEventEmitter<HTMLElement>;
}