diff --git a/css/xterm.css b/css/xterm.css
index 38e27a006c..ab3965b488 100644
--- a/css/xterm.css
+++ b/css/xterm.css
@@ -173,3 +173,8 @@
.xterm-strikethrough {
text-decoration: line-through;
}
+
+.xterm-screen .xterm-decoration-container .xterm-decoration {
+ z-index: 6;
+ position: absolute;
+}
diff --git a/demo/client.ts b/demo/client.ts
index 58d719a182..a8283461dd 100644
--- a/demo/client.ts
+++ b/demo/client.ts
@@ -149,6 +149,7 @@ if (document.location.pathname === '/test') {
document.getElementById('serialize').addEventListener('click', serializeButtonHandler);
document.getElementById('custom-glyph').addEventListener('click', writeCustomGlyphHandler);
document.getElementById('load-test').addEventListener('click', loadTest);
+ document.getElementById('add-decoration').addEventListener('click', addDecoration);
}
function createTerminal(): void {
@@ -525,3 +526,12 @@ function loadTest() {
term._core._onData.fire('\x03');
});
}
+
+function addDecoration() {
+ const marker = term.addMarker(1);
+ const decoration = term.registerDecoration({ marker });
+ term.write('');
+ decoration.onRender(() => {
+ decoration.element.style.backgroundColor = 'red';
+ });
+}
diff --git a/demo/index.html b/demo/index.html
index 9c86783b52..aa28000b28 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -64,6 +64,7 @@
Test
+
diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts
index 509bb2acf5..703c995be3 100644
--- a/src/browser/Terminal.ts
+++ b/src/browser/Terminal.ts
@@ -37,7 +37,7 @@ import * as Strings from 'browser/LocalizableStrings';
import { SoundService } from 'browser/services/SoundService';
import { MouseZoneManager } from 'browser/MouseZoneManager';
import { AccessibilityManager } from './AccessibilityManager';
-import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider } from 'xterm';
+import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider, IDecorationOptions, IDecoration } from 'xterm';
import { DomRenderer } from 'browser/renderer/dom/DomRenderer';
import { KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, ScrollSource, IColorEvent, ColorIndex, ColorRequestType } from 'common/Types';
import { evaluateKeyboardEvent } from 'common/input/Keyboard';
@@ -45,7 +45,7 @@ import { EventEmitter, IEvent, forwardEvent } from 'common/EventEmitter';
import { DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine';
import { ColorManager } from 'browser/ColorManager';
import { RenderService } from 'browser/services/RenderService';
-import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService, ICoreBrowserService, ICharacterJoinerService } from 'browser/services/Services';
+import { ICharSizeService, IRenderService, IMouseService, ISelectionService, ISoundService, ICoreBrowserService, ICharacterJoinerService, IDecorationService } from 'browser/services/Services';
import { CharSizeService } from 'browser/services/CharSizeService';
import { IBuffer } from 'common/buffer/Types';
import { MouseService } from 'browser/services/MouseService';
@@ -55,6 +55,7 @@ import { CoreTerminal } from 'common/CoreTerminal';
import { color, rgba } from 'browser/Color';
import { CharacterJoinerService } from 'browser/services/CharacterJoinerService';
import { toRgbString } from 'common/input/XParseColor';
+import { DecorationService } from 'browser/services/DecorationService';
// Let it work inside Node.js for automated testing purposes.
const document: Document = (typeof window !== 'undefined') ? window.document : null as any;
@@ -108,6 +109,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
public linkifier: ILinkifier;
public linkifier2: ILinkifier2;
public viewport: IViewport | undefined;
+ public decorationService: IDecorationService;
private _compositionHelper: ICompositionHelper | undefined;
private _mouseZoneManager: IMouseZoneManager | undefined;
private _accessibilityManager: AccessibilityManager | undefined;
@@ -157,6 +159,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.linkifier = this._instantiationService.createInstance(Linkifier);
this.linkifier2 = this.register(this._instantiationService.createInstance(Linkifier2));
+ this.decorationService = this.register(this._instantiationService.createInstance(DecorationService));
// Setup InputHandler listeners
this.register(this._inputHandler.onRequestBell(() => this.bell()));
@@ -574,6 +577,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.linkifier.attachToDom(this.element, this._mouseZoneManager);
this.linkifier2.attachToDom(this.screenElement, this._mouseService, this._renderService);
+ this.decorationService.attachToDom(this.screenElement, this._renderService, this._bufferService);
// This event listener must be registered aftre MouseZoneManager is created
this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.onMouseDown(e)));
@@ -998,6 +1002,10 @@ export class Terminal extends CoreTerminal implements ITerminal {
return this.buffer.addMarker(this.buffer.ybase + this.buffer.y + cursorYOffset);
}
+ public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined {
+ return this.decorationService!.registerDecoration(decorationOptions);
+ }
+
/**
* Gets whether the terminal has an active selection.
*/
diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts
index ee266e9c6b..10a1435b81 100644
--- a/src/browser/TestUtils.test.ts
+++ b/src/browser/TestUtils.test.ts
@@ -3,7 +3,7 @@
* @license MIT
*/
-import { IDisposable, IMarker, ISelectionPosition, ILinkProvider } from 'xterm';
+import { IDisposable, IMarker, ISelectionPosition, ILinkProvider, IDecorationOptions, IDecoration } from 'xterm';
import { IEvent, EventEmitter } from 'common/EventEmitter';
import { ICharacterJoinerService, ICharSizeService, IMouseService, IRenderService, ISelectionService } from 'browser/services/Services';
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types';
@@ -102,6 +102,9 @@ export class MockTerminal implements ITerminal {
public registerLinkProvider(linkProvider: ILinkProvider): IDisposable {
throw new Error('Method not implemented.');
}
+ public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined {
+ throw new Error('Method not implemented.');
+ }
public hasSelection(): boolean {
throw new Error('Method not implemented.');
}
@@ -283,6 +286,9 @@ export class MockRenderer implements IRenderer {
public setColors(colors: IColorSet): void {
throw new Error('Method not implemented.');
}
+ public registerDecoration(decorationOptions: IDecorationOptions): IDecoration {
+ throw new Error('Method not implemented.');
+ }
public onResize(cols: number, rows: number): void { }
public onCharSizeChanged(): void { }
public onBlur(): void { }
@@ -422,6 +428,9 @@ export class MockRenderService implements IRenderService {
public dispose(): void {
throw new Error('Method not implemented.');
}
+ public registerDecoration(decorationOptions: IDecorationOptions): IDecoration {
+ throw new Error('Method not implemented.');
+ }
}
export class MockCharacterJoinerService implements ICharacterJoinerService {
diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts
index a61658406c..35b52d6282 100644
--- a/src/browser/Types.d.ts
+++ b/src/browser/Types.d.ts
@@ -3,11 +3,11 @@
* @license MIT
*/
-import { IDisposable, IMarker, ISelectionPosition } from 'xterm';
+import { IDecorationOptions, IDecoration, IDisposable, IMarker, ISelectionPosition } from 'xterm';
import { IEvent } from 'common/EventEmitter';
import { ICoreTerminal, CharData, ITerminalOptions } from 'common/Types';
import { IMouseService, IRenderService } from './services/Services';
-import { IBuffer, IBufferSet } from 'common/buffer/Types';
+import { IBuffer } from 'common/buffer/Types';
import { IFunctionIdentifier, IParams } from 'common/parser/Types';
export interface ITerminal extends IPublicTerminal, ICoreTerminal {
@@ -61,6 +61,7 @@ export interface IPublicTerminal extends IDisposable {
registerCharacterJoiner(handler: (text: string) => [number, number][]): number;
deregisterCharacterJoiner(joinerId: number): void;
addMarker(cursorYOffset: number): IMarker | undefined;
+ registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined;
hasSelection(): boolean;
getSelection(): string;
getSelectionPosition(): ISelectionPosition | undefined;
diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts
index 117805f929..9571afa660 100644
--- a/src/browser/public/Terminal.ts
+++ b/src/browser/public/Terminal.ts
@@ -3,7 +3,7 @@
* @license MIT
*/
-import { Terminal as ITerminalApi, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, FontWeight, IModes } from 'xterm';
+import { Terminal as ITerminalApi, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBufferNamespace as IBufferNamespaceApi, IParser, ILinkProvider, IUnicodeHandling, FontWeight, IModes, IDecorationOptions, IDecoration } from 'xterm';
import { ITerminal } from 'browser/Types';
import { Terminal as TerminalCore } from 'browser/Terminal';
import * as Strings from 'browser/LocalizableStrings';
@@ -171,6 +171,11 @@ export class Terminal implements ITerminalApi {
this._verifyIntegers(cursorYOffset);
return this._core.addMarker(cursorYOffset);
}
+ public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined {
+ this._checkProposedApi();
+ this._verifyPositiveIntegers(decorationOptions.x ?? 0, decorationOptions.width ?? 0, decorationOptions.height ?? 0);
+ return this._core.registerDecoration(decorationOptions);
+ }
public addMarker(cursorYOffset: number): IMarker | undefined {
return this.registerMarker(cursorYOffset);
}
@@ -281,4 +286,12 @@ export class Terminal implements ITerminalApi {
}
}
}
+
+ private _verifyPositiveIntegers(...values: number[]): void {
+ for (const value of values) {
+ if (value && (value === Infinity || isNaN(value) || value % 1 !== 0 || value < 0)) {
+ throw new Error('This API only accepts positive integers');
+ }
+ }
+ }
}
diff --git a/src/browser/renderer/Renderer.ts b/src/browser/renderer/Renderer.ts
index 7a64257da7..a58893b4ca 100644
--- a/src/browser/renderer/Renderer.ts
+++ b/src/browser/renderer/Renderer.ts
@@ -10,10 +10,11 @@ import { IRenderLayer, IRenderer, IRenderDimensions, IRequestRedrawEvent } from
import { LinkRenderLayer } from 'browser/renderer/LinkRenderLayer';
import { Disposable } from 'common/Lifecycle';
import { IColorSet, ILinkifier, ILinkifier2 } from 'browser/Types';
-import { ICharSizeService, ICoreBrowserService } from 'browser/services/Services';
-import { IBufferService, IOptionsService, ICoreService, IInstantiationService } from 'common/services/Services';
+import { ICharSizeService } from 'browser/services/Services';
+import { IBufferService, IOptionsService, IInstantiationService } from 'common/services/Services';
import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache';
import { EventEmitter, IEvent } from 'common/EventEmitter';
+import { IDecorationOptions, IDecoration } from 'xterm';
let nextRendererId = 1;
diff --git a/src/browser/services/DecorationService.ts b/src/browser/services/DecorationService.ts
new file mode 100644
index 0000000000..f29ec7ea1d
--- /dev/null
+++ b/src/browser/services/DecorationService.ts
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) 2022 The xterm.js authors. All rights reserved.
+ * @license MIT
+ */
+
+import { IDecorationService, IRenderService } from 'browser/services/Services';
+import { EventEmitter, IEvent } from 'common/EventEmitter';
+import { Disposable } from 'common/Lifecycle';
+import { IBufferService, IInstantiationService } from 'common/services/Services';
+import { IDecorationOptions, IDecoration, IMarker } from 'xterm';
+
+export class DecorationService extends Disposable implements IDecorationService {
+
+ private readonly _decorations: Decoration[] = [];
+ private _container: HTMLElement | undefined;
+ private _screenElement: HTMLElement | undefined;
+ private _renderService: IRenderService | undefined;
+
+ constructor(
+ @IBufferService private readonly _bufferService: IBufferService,
+ @IInstantiationService private readonly _instantiationService: IInstantiationService) {
+ super();
+ }
+
+ public attachToDom(screenElement: HTMLElement, renderService: IRenderService): void {
+ this._renderService = renderService;
+ this._screenElement = screenElement;
+ this._container = document.createElement('div');
+ this._container.classList.add('xterm-decoration-container');
+ screenElement.appendChild(this._container);
+ this.refresh();
+ this.register(this._renderService.onRenderedBufferChange(() => this.refresh()));
+ this.register(this._renderService.onDimensionsChange(() => this.refresh(true)));
+ }
+
+ public registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined {
+ if (decorationOptions.marker.isDisposed || !this._container) {
+ return undefined;
+ }
+ const decoration = this._instantiationService.createInstance(Decoration, decorationOptions, this._container);
+ this._decorations.push(decoration);
+ decoration.onDispose(() => this._decorations.splice(this._decorations.indexOf(decoration), 1));
+ return decoration;
+ }
+
+ public refresh(recreate?: boolean): void {
+ if (!this._bufferService || !this._renderService) {
+ return;
+ }
+ for (const decoration of this._decorations) {
+ decoration.render(this._renderService, recreate);
+ }
+ }
+
+ public dispose(): void {
+ for (const decoration of this._decorations) {
+ decoration.dispose();
+ }
+ if (this._container) {
+ this._screenElement?.removeChild(this._container);
+ }
+ }
+}
+export class Decoration extends Disposable implements IDecoration {
+ private static _nextId = 1;
+ private readonly _marker: IMarker;
+ private _element: HTMLElement | undefined;
+ private readonly _id: number = Decoration._nextId++;
+ public isDisposed: boolean = false;
+
+ public get element(): HTMLElement | undefined { return this._element; }
+ public get marker(): IMarker { return this._marker; }
+
+ private _onDispose = new EventEmitter();
+ public get onDispose(): IEvent { return this._onDispose.event; }
+
+ private _onRender = new EventEmitter();
+ public get onRender(): IEvent { return this._onRender.event; }
+
+ public x: number;
+ public anchor: 'left' | 'right';
+ public width: number;
+ public height: number;
+
+ constructor(
+ options: IDecorationOptions,
+ private readonly _container: HTMLElement,
+ @IBufferService private readonly _bufferService: IBufferService
+ ) {
+ super();
+ this.x = options.x ?? 0;
+ this._marker = options.marker;
+ this.anchor = options.anchor || 'left';
+ this.width = options.width || 1;
+ this.height = options.height || 1;
+ }
+
+ public render(renderService: IRenderService, recreate?: boolean): void {
+ if (!this._element || recreate) {
+ this._createElement(renderService, recreate);
+ }
+ if (this._container && this._element && !this._container.contains(this._element)) {
+ this._container.append(this._element);
+ }
+ this._refreshStyle(renderService);
+ this._onRender.fire(this._element!);
+ }
+
+ private _createElement(renderService: IRenderService, recreate?: boolean): void {
+ if (recreate && this._element) {
+ this._container.removeChild(this._element);
+ }
+ this._element = document.createElement('div');
+ this._element.classList.add('xterm-decoration');
+ this._element.style.width = `${this.width * renderService.dimensions.scaledCellWidth}px`;
+ this._element.style.height = `${this.height * renderService.dimensions.scaledCellHeight}px`;
+ this._element.style.top = `${(this.marker.line - this._bufferService.buffers.active.ydisp) * renderService.dimensions.scaledCellHeight}px`;
+
+ if (this.x && this.x > this._bufferService.cols) {
+ this._element!.style.display = 'none';
+ }
+ if (this.anchor === 'right') {
+ this._element.style.right = this.x ? `${this.x * renderService.dimensions.scaledCellWidth}px` : '';
+ } else {
+ this._element.style.left = this.x ? `${this.x * renderService.dimensions.scaledCellWidth}px` : '';
+ }
+ this.register({
+ dispose: () => {
+ if (this.isDisposed) {
+ return;
+ }
+ this._container.removeChild(this._element!);
+ this.isDisposed = true;
+ this._marker.dispose();
+ // Emit before super.dispose such that dispose listeners get a change to react
+ this._onDispose.fire();
+ super.dispose();
+ }
+ });
+ }
+
+ private _refreshStyle(renderService: IRenderService): void {
+ const line = this.marker.line - this._bufferService.buffers.active.ydisp;
+ if (line < 0 || line > this._bufferService.rows) {
+ // outside of viewport
+ this._element!.style.display = 'none';
+ } else {
+ this._element!.style.top = `${line * renderService.dimensions.scaledCellHeight}px`;
+ this._element!.style.display = 'block';
+ }
+ }
+}
diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts
index 4928fa28ec..7faf3f0f69 100644
--- a/src/browser/services/Services.ts
+++ b/src/browser/services/Services.ts
@@ -9,6 +9,8 @@ import { IColorSet } from 'browser/Types';
import { ISelectionRedrawRequestEvent as ISelectionRequestRedrawEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types';
import { createDecorator } from 'common/services/ServiceRegistry';
import { IDisposable } from 'common/Types';
+import { IDecorationOptions, IDecoration } from 'xterm';
+import { IBufferService } from 'common/services/Services';
export const ICharSizeService = createDecorator('CharSizeService');
export interface ICharSizeService {
@@ -113,3 +115,11 @@ export interface ICharacterJoinerService {
deregister(joinerId: number): boolean;
getJoinedCharacters(row: number): [number, number][];
}
+
+
+export const IDecorationService = createDecorator('DecorationService');
+export interface IDecorationService extends IDisposable {
+ registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined;
+ refresh(): void;
+ attachToDom(screenElement: HTMLElement, renderService: IRenderService, bufferService: IBufferService): void;
+}
diff --git a/test/api/Terminal.api.ts b/test/api/Terminal.api.ts
index 1fe7545680..ee6a0cfaaf 100644
--- a/test/api/Terminal.api.ts
+++ b/test/api/Terminal.api.ts
@@ -731,6 +731,52 @@ describe('API Integration Tests', function(): void {
await pollFor(page, `window.term._core._renderService.dimensions.actualCellWidth > 0`, true);
});
+ describe('registerDecoration', () => {
+ it('should register decorations and render them', async () => {
+ await openTerminal(page);
+ await writeSync(page, '\\n\\n\\n\\n');
+ await writeSync(page, '\\n\\n\\n\\n');
+ await writeSync(page, '\\n\\n\\n\\n');
+ await page.evaluate(`window.marker1 = window.term.addMarker(1)`);
+ await page.evaluate(`window.marker2 = window.term.addMarker(2)`);
+ await page.evaluate(`window.term.registerDecoration({ marker: window.marker1 })`);
+ await page.evaluate(`window.term.registerDecoration({ marker: window.marker2 })`);
+ await page.evaluate(`window.term.resize(10, 5)`);
+ assert.equal(await page.evaluate(`document.querySelectorAll('.xterm-screen .xterm-decoration').length`), 2);
+ });
+ it('on resize should dispose of the old decoration and create a new one', async () => {
+ await openTerminal(page);
+ await writeSync(page, '\\n\\n\\n\\n');
+ await writeSync(page, '\\n\\n\\n\\n');
+ await page.evaluate(`window.marker = window.term.addMarker(1)`);
+ await page.evaluate(`window.decoration = window.term.registerDecoration({ marker: window.marker })`);
+ await page.evaluate(`window.term.resize(10, 5)`);
+ assert.equal(await page.evaluate(`document.querySelectorAll('.xterm-screen .xterm-decoration').length`), 1);
+ });
+ it('should return undefined when the marker has already been disposed of', async () => {
+ await openTerminal(page);
+ await writeSync(page, '\\n\\n\\n\\n');
+ await writeSync(page, '\\n\\n\\n\\n');
+ await page.evaluate(`window.marker = window.term.addMarker(1)`);
+ await page.evaluate(`window.marker.dispose()`);
+ assert.equal(await page.evaluate(`window.decoration = window.term.registerDecoration({ marker: window.marker });`), undefined);
+ });
+ it('should throw when a negative x offset is provided', async () => {
+ await openTerminal(page);
+ await writeSync(page, '\\n\\n\\n\\n');
+ await writeSync(page, '\\n\\n\\n\\n');
+ await page.evaluate(`window.marker = window.term.addMarker(1)`);
+ await page.evaluate(`
+ try {
+ window.decoration = window.term.registerDecoration({ marker: window.marker, x: -2 });
+ } catch (e) {
+ window.throwMessage = e.message;
+ }
+ `);
+ await pollFor(page, 'window.throwMessage', 'This API only accepts positive integers');
+ });
+ });
+
describe('registerLinkProvider', () => {
it('should fire provideLinks when hovering cells', async () => {
await openTerminal(page, { rendererType: 'dom' });
diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts
index 39245afe5e..17bf8d5013 100644
--- a/typings/xterm.d.ts
+++ b/typings/xterm.d.ts
@@ -380,29 +380,96 @@ declare module 'xterm' {
* is trimmed and lines are added or removed. This is a single line that may
* be part of a larger wrapped line.
*/
- export interface IMarker extends IDisposable {
+ export interface IMarker extends IDisposableWithEvent {
/**
* A unique identifier for this marker.
*/
readonly id: number;
- /**
- * Whether this marker is disposed.
- */
- readonly isDisposed: boolean;
-
/**
* The actual line index in the buffer at this point in time. This is set to
* -1 if the marker has been disposed.
*/
readonly line: number;
+ }
+ /**
+ * Represents a disposable with an
+ * @param onDispose event listener and
+ * @param isDisposed property.
+ */
+ export interface IDisposableWithEvent extends IDisposable {
/**
- * Event listener to get notified when the marker gets disposed. Automatic disposal
- * might happen for a marker, that got invalidated by scrolling out or removal of
- * a line from the buffer.
+ * Event listener to get notified when this gets disposed.
*/
onDispose: IEvent;
+
+ /**
+ * Whether this is disposed.
+ */
+ readonly isDisposed: boolean;
+ }
+
+ /**
+ * Represents a decoration in the terminal that is associated with a particular marker and DOM element.
+ */
+ export interface IDecoration extends IDisposableWithEvent {
+ /*
+ * The marker for the decoration in the terminal.
+ */
+ readonly marker: IMarker;
+
+ /**
+ * An event fired when the decoration
+ * is rendered, returns the dom element
+ * associated with the decoration.
+ */
+ readonly onRender: IEvent;
+
+ /**
+ * The HTMLElement that gets created after the
+ * first _onRender call, or undefined if accessed before
+ * that.
+ */
+ readonly element: HTMLElement | undefined;
+ }
+
+ /**
+ * Options provided when registering a decoration
+ * containing a @param marker, @param anchor,
+ * @param x offset from the anchor, @param width in cells
+ * and @param height in cells.
+ */
+ export interface IDecorationOptions {
+ /**
+ * The line in the terminal where
+ * the decoration will be displayed
+ */
+ marker: IMarker;
+
+ /*
+ * Where the decoration will be anchored -
+ * defaults to the left edge
+ */
+ anchor?: 'right' | 'left';
+
+ /**
+ * The x position offset relative to the anchor
+ */
+ x?: number;
+
+
+ /**
+ * The width of the decoration in cells, which defaults to
+ * cell width
+ */
+ width?: number;
+
+ /**
+ * The height of the decoration in cells, which defaults to
+ * cell height
+ */
+ height?: number;
}
/**
@@ -870,6 +937,15 @@ declare module 'xterm' {
*/
addMarker(cursorYOffset: number): IMarker | undefined;
+ /**
+ * (EXPERIMENTAL) Adds a decoration to the terminal using
+ * @param decorationOptions, which takes a marker and an optional anchor,
+ * width, height, and x offset from the anchor. Returns the decoration or
+ * undefined if the alt buffer is active or the marker has already been disposed of.
+ * @throws when options include a negative x offset.
+ */
+ registerDecoration(decorationOptions: IDecorationOptions): IDecoration | undefined;
+
/**
* Gets whether the terminal has an active selection.
*/