From 37e67848565f1947457ab32bfd4518db7fccae90 Mon Sep 17 00:00:00 2001 From: Adam Kariv Date: Thu, 8 Apr 2021 06:08:00 +0000 Subject: [PATCH 1/4] wip decorations --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 4 ++ src/browser/Terminal.ts | 19 +++++- src/browser/TestUtils.test.ts | 12 +++- src/browser/Types.d.ts | 5 +- src/browser/renderer/BaseRenderLayer.ts | 1 + src/browser/renderer/DecorationRenderLayer.ts | 60 +++++++++++++++++ src/browser/renderer/Renderer.ts | 10 ++- src/browser/renderer/Types.d.ts | 6 ++ src/browser/renderer/dom/DomRenderer.ts | 4 ++ src/browser/services/DecorationService.ts | 65 +++++++++++++++++++ src/browser/services/RenderService.ts | 4 ++ src/browser/services/Services.ts | 13 +++- src/common/Types.d.ts | 10 +++ 13 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 src/browser/renderer/DecorationRenderLayer.ts create mode 100644 src/browser/services/DecorationService.ts diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 3d25e5b0c6..02539d44c6 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -204,6 +204,10 @@ export class WebglRenderer extends Disposable implements IRenderer { this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1 }); } + public onDecorationsChanged(): void { + // TBD + } + public onCursorMove(): void { for (const l of this._renderLayers) { l.onCursorMove(this._terminal); diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 6400743c7a..3ab2a82d2c 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -39,13 +39,13 @@ import { MouseZoneManager } from 'browser/MouseZoneManager'; import { AccessibilityManager } from './AccessibilityManager'; import { ITheme, IMarker, IDisposable, ISelectionPosition, ILinkProvider } from 'xterm'; import { DomRenderer } from 'browser/renderer/dom/DomRenderer'; -import { IKeyboardEvent, KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, ScrollSource, IAnsiColorChangeEvent } from 'common/Types'; +import { IKeyboardEvent, KeyboardResultType, CoreMouseEventType, CoreMouseButton, CoreMouseAction, ITerminalOptions, ScrollSource, IAnsiColorChangeEvent, IDecorationElement, IDecorationHandle } from 'common/Types'; import { evaluateKeyboardEvent } from 'common/input/Keyboard'; 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 { ITerminalOptions as IInitializedTerminalOptions } from 'common/services/Services'; import { rgba } from 'browser/Color'; import { CharacterJoinerService } from 'browser/services/CharacterJoinerService'; +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; @@ -86,6 +87,7 @@ export class Terminal extends CoreTerminal implements ITerminal { private _characterJoinerService: ICharacterJoinerService | undefined; private _selectionService: ISelectionService | undefined; private _soundService: ISoundService | undefined; + private _decorationService: IDecorationService | undefined; /** * Records whether the keydown event has already been handled and triggered a data event, if so @@ -518,6 +520,9 @@ export class Terminal extends CoreTerminal implements ITerminal { })); this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this._selectionService!.refresh())); + this._decorationService = this.register(this._instantiationService.createInstance(DecorationService)); + this._instantiationService.setService(IDecorationService, this._decorationService); + this._mouseZoneManager = this._instantiationService.createInstance(MouseZoneManager, this.element, this.screenElement); this.register(this._mouseZoneManager); this.register(this.onScroll(() => this._mouseZoneManager!.clearAll())); @@ -1280,6 +1285,16 @@ export class Terminal extends CoreTerminal implements ITerminal { // return this.options.bellStyle === 'sound' || // this.options.bellStyle === 'both'; } + + public addDecoration(element: IDecorationElement): IDecorationHandle | undefined{ + return this._decorationService?.addDecoration(element); + } + public removeDeoration(handle: IDecorationHandle): boolean { + return !!(this._decorationService?.removeDeoration(handle)); + } + public clearDecorations(): number { + return this._decorationService?.clearDecorations() || 0; + } } /** diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index f9ad2a7de3..7a70c02d9c 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -9,7 +9,7 @@ import { ICharacterJoinerService, ICharSizeService, IMouseService, IRenderServic import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types'; import { IColorSet, ILinkMatcherOptions, ITerminal, ILinkifier, ILinkifier2, IBrowser, IViewport, IColorManager, ICompositionHelper, CharacterJoinerHandler } from 'browser/Types'; import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; -import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, ITerminalOptions } from 'common/Types'; +import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener, ICharset, ITerminalOptions, IDecorationElement } from 'common/Types'; import { Buffer } from 'common/buffer/Buffer'; import * as Browser from 'common/Platform'; import { Terminal } from 'browser/Terminal'; @@ -198,6 +198,15 @@ export class MockTerminal implements ITerminal { } public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } public deregisterCharacterJoiner(joinerId: number): void { } + public addDecoration(element: IDecorationElement): number | undefined { + throw new Error('Method not implemented.'); + } + public removeDeoration(handle: number): boolean { + throw new Error('Method not implemented.'); + } + public clearDecorations(): number { + throw new Error('Method not implemented.'); + } } export class MockBuffer implements IBuffer { @@ -280,6 +289,7 @@ export class MockRenderer implements IRenderer { public onBlur(): void { } public onFocus(): void { } public onSelectionChanged(start: [number, number], end: [number, number]): void { } + public onDecorationsChanged(): void { } public onCursorMove(): void { } public onOptionsChanged(): void { } public onDevicePixelRatioChange(): void { } diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index b2ff29d758..302c234a30 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -5,7 +5,7 @@ import { IDisposable, IMarker, ISelectionPosition } from 'xterm'; import { IEvent } from 'common/EventEmitter'; -import { ICoreTerminal, CharData, ITerminalOptions } from 'common/Types'; +import { ICoreTerminal, CharData, ITerminalOptions, IDecorationElement, IDecorationHandle } from 'common/Types'; import { IMouseService, IRenderService } from './services/Services'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { IFunctionIdentifier, IParams } from 'common/parser/Types'; @@ -81,6 +81,9 @@ export interface IPublicTerminal extends IDisposable { paste(data: string): void; refresh(start: number, end: number): void; reset(): void; + addDecoration(element: IDecorationElement): IDecorationHandle | undefined; + removeDeoration(handle: IDecorationHandle): boolean; + clearDecorations(): number; } export type CustomKeyEventHandler = (event: KeyboardEvent) => boolean; diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index ef869ef3fe..c8e12111cd 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -79,6 +79,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { public onCursorMove(): void {} public onGridChanged(startRow: number, endRow: number): void {} public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean = false): void {} + public onDecorationsChanged(): void {} public setColors(colorSet: IColorSet): void { this._refreshCharAtlas(colorSet); diff --git a/src/browser/renderer/DecorationRenderLayer.ts b/src/browser/renderer/DecorationRenderLayer.ts new file mode 100644 index 0000000000..2561188218 --- /dev/null +++ b/src/browser/renderer/DecorationRenderLayer.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IRenderDimensions } from 'browser/renderer/Types'; +import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer'; +import { IColorSet } from 'browser/Types'; +import { IBufferService, IOptionsService } from 'common/services/Services'; +import { IDecorationService } from 'browser/services/Services'; + + +export class DecorationRenderLayer extends BaseRenderLayer { + + private _decorationService: IDecorationService; + + constructor( + container: HTMLElement, + zIndex: number, + colors: IColorSet, + rendererId: number, + @IDecorationService decorationService: IDecorationService, + @IBufferService bufferService: IBufferService, + @IOptionsService optionsService: IOptionsService, + ) { + super(container, 'decorations', zIndex, true, colors, rendererId, bufferService, optionsService); + this._decorationService = decorationService; + } + + public reset(): void { + this._clearAll(); + } + + public onDecorationsChanged(): void { + // Remove all decorations + this._clearAll(); + + this._decorationService.forEachDecoration((element) => { + // Translate from buffer position to viewport position + const viewportStartRow = element.startRow - this._bufferService.buffer.ydisp; + const viewportEndRow = element.endRow - this._bufferService.buffer.ydisp; + const viewportCappedStartRow = Math.max(viewportStartRow, 0); + const viewportCappedEndRow = Math.min(viewportEndRow, this._bufferService.rows - 1); + const width = element.endColumn - element.startColumn; + const height = viewportCappedEndRow - viewportCappedStartRow + 1; + if (viewportStartRow <= viewportEndRow) { + if (element.fillStyle) { + this._ctx.fillStyle = element.fillStyle; + this._fillCells(element.startColumn, viewportCappedStartRow, width, height); + } + if (element.strokeStyle) { + this._ctx.strokeStyle = element.strokeStyle; + this._strokeRectAtCell(element.startColumn, viewportCappedStartRow, width, height); + } + } + return false; + }); + } + +} diff --git a/src/browser/renderer/Renderer.ts b/src/browser/renderer/Renderer.ts index d5de40db81..89eb00eb9a 100644 --- a/src/browser/renderer/Renderer.ts +++ b/src/browser/renderer/Renderer.ts @@ -14,6 +14,7 @@ import { ICharSizeService, ICoreBrowserService } from 'browser/services/Services import { IBufferService, IOptionsService, ICoreService, IInstantiationService } from 'common/services/Services'; import { removeTerminalFromCache } from 'browser/renderer/atlas/CharAtlasCache'; import { EventEmitter, IEvent } from 'common/EventEmitter'; +import { DecorationRenderLayer } from 'browser/renderer/DecorationRenderLayer'; let nextRendererId = 1; @@ -36,7 +37,7 @@ export class Renderer extends Disposable implements IRenderer { @IInstantiationService instantiationService: IInstantiationService, @IBufferService private readonly _bufferService: IBufferService, @ICharSizeService private readonly _charSizeService: ICharSizeService, - @IOptionsService private readonly _optionsService: IOptionsService + @IOptionsService private readonly _optionsService: IOptionsService, ) { super(); const allowTransparency = this._optionsService.options.allowTransparency; @@ -44,7 +45,8 @@ export class Renderer extends Disposable implements IRenderer { instantiationService.createInstance(TextRenderLayer, this._screenElement, 0, this._colors, allowTransparency, this._id), instantiationService.createInstance(SelectionRenderLayer, this._screenElement, 1, this._colors, this._id), instantiationService.createInstance(LinkRenderLayer, this._screenElement, 2, this._colors, this._id, linkifier, linkifier2), - instantiationService.createInstance(CursorRenderLayer, this._screenElement, 3, this._colors, this._id, this._onRequestRedraw) + instantiationService.createInstance(DecorationRenderLayer, this._screenElement, 3, this._colors, this._id), + instantiationService.createInstance(CursorRenderLayer, this._screenElement, 4, this._colors, this._id, this._onRequestRedraw), ]; this.dimensions = { scaledCharWidth: 0, @@ -121,6 +123,10 @@ export class Renderer extends Disposable implements IRenderer { this._runOperation(l => l.onSelectionChanged(start, end, columnSelectMode)); } + public onDecorationsChanged(): void { + this._runOperation(l => l.onDecorationsChanged()); + } + public onCursorMove(): void { this._runOperation(l => l.onCursorMove()); } diff --git a/src/browser/renderer/Types.d.ts b/src/browser/renderer/Types.d.ts index fc137bc8ff..fd08189738 100644 --- a/src/browser/renderer/Types.d.ts +++ b/src/browser/renderer/Types.d.ts @@ -48,6 +48,7 @@ export interface IRenderer extends IDisposable { onBlur(): void; onFocus(): void; onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; + onDecorationsChanged(): void; onCursorMove(): void; onOptionsChanged(): void; clear(): void; @@ -91,6 +92,11 @@ export interface IRenderLayer extends IDisposable { */ onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; + /** + * Called when decorations change + */ + onDecorationsChanged(): void; + /** * Resize the render layer. */ diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index dccdb8775f..723169bb0e 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -337,6 +337,10 @@ export class DomRenderer extends Disposable implements IRenderer { return element; } + public onDecorationsChanged(): void { + // TBD + } + public onCursorMove(): void { // No-op, the cursor is drawn when rows are drawn } diff --git a/src/browser/services/DecorationService.ts b/src/browser/services/DecorationService.ts new file mode 100644 index 0000000000..fc60ab61ec --- /dev/null +++ b/src/browser/services/DecorationService.ts @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { RenderDebouncer } from 'browser/RenderDebouncer'; +import { EventEmitter, IEvent } from 'common/EventEmitter'; +import { Disposable } from 'common/Lifecycle'; +import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; +import { addDisposableDomListener } from 'browser/Lifecycle'; +import { IColorSet } from 'browser/Types'; +import { IOptionsService, IBufferService } from 'common/services/Services'; +import { ICharSizeService, IDecorationService } from 'browser/services/Services'; +import { IDecorationElement, IDecorationHandle } from 'common/Types'; + +interface IDecorationRegistration { + handle: IDecorationHandle; + element: IDecorationElement; +} + + +export class DecorationService extends Disposable implements IDecorationService { + public serviceBrand: undefined; + + private _activeDecorations: IDecorationRegistration[] = []; + + constructor() { + super(); + } + + public addDecoration(element: IDecorationElement): number { + const registration: IDecorationRegistration = { + handle: this._activeDecorations.length, + element: element + }; + this._activeDecorations[registration.handle] = registration; + return registration.handle; + } + + public removeDeoration(handle: IDecorationHandle): boolean { + for (let index = 0 ; index < this._activeDecorations.length ; index++) { + const reg = this._activeDecorations[index]; + if (reg.handle === handle) { + this._activeDecorations.splice(index, 1); + return true; + } + } + return false; + } + + public forEachDecoration(callback: (decoration: IDecorationElement) => boolean): void { + for (const reg of this._activeDecorations) { + if (callback(reg.element)) { + return; + } + } + } + + public clearDecorations(): number { + const count = this._activeDecorations.length; + this._activeDecorations = []; + return count; + } +} diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index fc2eb43540..3441ab3163 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -207,6 +207,10 @@ export class RenderService extends Disposable implements IRenderService { this._renderer.onSelectionChanged(start, end, columnSelectMode); } + public onDecorationsChanged(): void { + this._renderer.onDecorationsChanged(); + } + public onCursorMove(): void { this._renderer.onCursorMove(); } diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 8c8a7bd9bd..12e4a09e23 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -8,7 +8,7 @@ import { IRenderDimensions, IRenderer } from 'browser/renderer/Types'; 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 { IDecorationHandle, IDecorationElement, IDisposable } from 'common/Types'; export const ICharSizeService = createDecorator('CharSizeService'); export interface ICharSizeService { @@ -103,7 +103,6 @@ export interface ISoundService { playBellSound(): void; } - export const ICharacterJoinerService = createDecorator('CharacterJoinerService'); export interface ICharacterJoinerService { serviceBrand: undefined; @@ -112,3 +111,13 @@ export interface ICharacterJoinerService { deregister(joinerId: number): boolean; getJoinedCharacters(row: number): [number, number][]; } + +export const IDecorationService = createDecorator('DecorationService'); +export interface IDecorationService { + serviceBrand: undefined; + + addDecoration(element: IDecorationElement): IDecorationHandle; + removeDeoration(handle: IDecorationHandle): boolean; + forEachDecoration(callback: (decoration: IDecorationElement) => boolean) : void; + clearDecorations(): number; +} diff --git a/src/common/Types.d.ts b/src/common/Types.d.ts index df29919560..1f32b7461c 100644 --- a/src/common/Types.d.ts +++ b/src/common/Types.d.ts @@ -448,3 +448,13 @@ interface IParseStack { decodedLength: number; position: number; } + +export type IDecorationHandle = number; +interface IDecorationElement { + startColumn: number; + endColumn: number; + startRow: number; + endRow: number; + fillStyle: string | CanvasGradient | CanvasPattern; + strokeStyle: string | CanvasGradient | CanvasPattern; +} From ec002e5d88677f06e7be59a8f502f82daf19489a Mon Sep 17 00:00:00 2001 From: Adam Kariv Date: Thu, 8 Apr 2021 12:12:08 +0000 Subject: [PATCH 2/4] more wip decorators --- demo/client.ts | 16 ++++++++++++++++ demo/index.html | 1 + src/browser/Terminal.ts | 20 ++++++++++++++------ src/browser/TestUtils.test.ts | 3 +++ src/browser/public/Terminal.ts | 12 +++++++++++- src/browser/services/DecorationService.ts | 17 ++++++----------- src/browser/services/RenderService.ts | 1 + src/browser/services/Services.ts | 1 + 8 files changed, 53 insertions(+), 18 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index 0bb124cd4d..f6db167172 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -52,6 +52,7 @@ let protocol; let socketURL; let socket; let pid; +let decorationHandle; type AddonType = 'attach' | 'fit' | 'search' | 'serialize' | 'unicode11' | 'web-links' | 'webgl' | 'ligatures'; @@ -147,6 +148,7 @@ if (document.location.pathname === '/test') { createTerminal(); document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler); document.getElementById('serialize').addEventListener('click', serializeButtonHandler); + document.getElementById('decorations').addEventListener('click', decorationsButtonHandler); } function createTerminal(): void { @@ -431,3 +433,17 @@ function serializeButtonHandler(): void { term.write(output); } } + +function decorationsButtonHandler(): void { + if (decorationHandle) { + term.removeDeoration(decorationHandle); + decorationHandle = null; + } else { + decorationHandle = term.addDecoration({ + startColumn: 3, endColumn: 13, + startRow: 3, endRow: 8, + fillStyle: 'rgba(255, 0, 0, 0.7)', + strokeStyle: 'rgba(0, 0, 255, 0.7)', + }); + } +} diff --git a/demo/index.html b/demo/index.html index ab5b204067..838f26ba7c 100644 --- a/demo/index.html +++ b/demo/index.html @@ -22,6 +22,7 @@

Options

+

Addons

Addons can be loaded and unloaded on a particular terminal to extend its functionality.

diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 3ab2a82d2c..5fa73ca3dc 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -458,6 +458,9 @@ export class Terminal extends CoreTerminal implements ITerminal { this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService); this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService); + this._decorationService = this.register(this._instantiationService.createInstance(DecorationService)); + this._instantiationService.setService(IDecorationService, this._decorationService); + const renderer = this._createRenderer(); this._renderService = this.register(this._instantiationService.createInstance(RenderService, renderer, this.rows, this.screenElement)); this._instantiationService.setService(IRenderService, this._renderService); @@ -517,12 +520,11 @@ export class Terminal extends CoreTerminal implements ITerminal { this.viewport!.syncScrollArea(); } this._selectionService!.refresh(); + console.log('SCROLL'); + this._renderService!.onDecorationsChanged(); })); this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this._selectionService!.refresh())); - this._decorationService = this.register(this._instantiationService.createInstance(DecorationService)); - this._instantiationService.setService(IDecorationService, this._decorationService); - this._mouseZoneManager = this._instantiationService.createInstance(MouseZoneManager, this.element, this.screenElement); this.register(this._mouseZoneManager); this.register(this.onScroll(() => this._mouseZoneManager!.clearAll())); @@ -1287,13 +1289,19 @@ export class Terminal extends CoreTerminal implements ITerminal { } public addDecoration(element: IDecorationElement): IDecorationHandle | undefined{ - return this._decorationService?.addDecoration(element); + const ret = this._decorationService?.addDecoration(element); + this._renderService?.onDecorationsChanged(); + return ret; } public removeDeoration(handle: IDecorationHandle): boolean { - return !!(this._decorationService?.removeDeoration(handle)); + const ret = !!(this._decorationService?.removeDeoration(handle)); + this._renderService?.onDecorationsChanged(); + return ret; } public clearDecorations(): number { - return this._decorationService?.clearDecorations() || 0; + const ret = this._decorationService?.clearDecorations() || 0; + this._renderService?.onDecorationsChanged(); + return ret; } } diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index 7a70c02d9c..67fc63941b 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -412,6 +412,9 @@ export class MockRenderService implements IRenderService { public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { throw new Error('Method not implemented.'); } + public onDecorationsChanged(): void { + throw new Error('Method not implemented.'); + } public onCursorMove(): void { throw new Error('Method not implemented.'); } diff --git a/src/browser/public/Terminal.ts b/src/browser/public/Terminal.ts index 1460645458..f375f21b68 100644 --- a/src/browser/public/Terminal.ts +++ b/src/browser/public/Terminal.ts @@ -5,7 +5,7 @@ import { Terminal as ITerminalApi, ITerminalOptions, IMarker, IDisposable, ILinkMatcherOptions, ITheme, ILocalizableStrings, ITerminalAddon, ISelectionPosition, IBuffer as IBufferApi, IBufferNamespace as IBufferNamespaceApi, IBufferLine as IBufferLineApi, IBufferCell as IBufferCellApi, IParser, IFunctionIdentifier, ILinkProvider, IUnicodeHandling, IUnicodeVersionProvider, FontWeight } from 'xterm'; import { ITerminal } from 'browser/Types'; -import { IBufferLine, ICellData } from 'common/Types'; +import { IBufferLine, ICellData, IDecorationElement, IDecorationHandle } from 'common/Types'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { CellData } from 'common/buffer/CellData'; import { Terminal as TerminalCore } from '../Terminal'; @@ -175,6 +175,16 @@ export class Terminal implements ITerminalApi { public paste(data: string): void { this._core.paste(data); } + public addDecoration(element: IDecorationElement): IDecorationHandle | undefined { + return this._core.addDecoration(element); + } + public removeDeoration(handle: IDecorationHandle): boolean { + return this._core.removeDeoration(handle); + } + public clearDecorations(): number { + return this._core.clearDecorations(); + } + public getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; public getOption(key: 'allowTransparency' | 'altClickMovesCursor' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'visualBell'): boolean; public getOption(key: 'cols' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): number; diff --git a/src/browser/services/DecorationService.ts b/src/browser/services/DecorationService.ts index fc60ab61ec..c559c6fd1b 100644 --- a/src/browser/services/DecorationService.ts +++ b/src/browser/services/DecorationService.ts @@ -3,15 +3,8 @@ * @license MIT */ -import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; -import { RenderDebouncer } from 'browser/RenderDebouncer'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; import { Disposable } from 'common/Lifecycle'; -import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; -import { addDisposableDomListener } from 'browser/Lifecycle'; -import { IColorSet } from 'browser/Types'; -import { IOptionsService, IBufferService } from 'common/services/Services'; -import { ICharSizeService, IDecorationService } from 'browser/services/Services'; +import { IDecorationService } from 'browser/services/Services'; import { IDecorationElement, IDecorationHandle } from 'common/Types'; interface IDecorationRegistration { @@ -22,6 +15,7 @@ interface IDecorationRegistration { export class DecorationService extends Disposable implements IDecorationService { public serviceBrand: undefined; + private _handle = 0; private _activeDecorations: IDecorationRegistration[] = []; @@ -30,12 +24,13 @@ export class DecorationService extends Disposable implements IDecorationService } public addDecoration(element: IDecorationElement): number { + this._handle += 1; const registration: IDecorationRegistration = { - handle: this._activeDecorations.length, + handle: this._handle, element: element }; - this._activeDecorations[registration.handle] = registration; - return registration.handle; + this._activeDecorations.push(registration); + return this._handle; } public removeDeoration(handle: IDecorationHandle): boolean { diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index 3441ab3163..047d30fcdd 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -118,6 +118,7 @@ export class RenderService extends Disposable implements IRenderService { this._renderer.onSelectionChanged(this._selectionState.start, this._selectionState.end, this._selectionState.columnSelectMode); this._needsSelectionRefresh = false; } + this._renderer.onDecorationsChanged(); // Fire render event only if it was not a redraw if (!this._isNextRenderRedrawOnly) { diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 12e4a09e23..11cb70110e 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -64,6 +64,7 @@ export interface IRenderService extends IDisposable { onBlur(): void; onFocus(): void; onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void; + onDecorationsChanged(): void; onCursorMove(): void; clear(): void; } From 22f75b7718c21987a5b3130b58be4f888690cd3a Mon Sep 17 00:00:00 2001 From: Adam Kariv Date: Thu, 8 Apr 2021 15:40:18 +0300 Subject: [PATCH 3/4] remove log print --- src/browser/Terminal.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index 5fa73ca3dc..aba62ffbaa 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -520,7 +520,6 @@ export class Terminal extends CoreTerminal implements ITerminal { this.viewport!.syncScrollArea(); } this._selectionService!.refresh(); - console.log('SCROLL'); this._renderService!.onDecorationsChanged(); })); this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this._selectionService!.refresh())); From 916d55ee21a0628199f24b0030144e6ba08871fa Mon Sep 17 00:00:00 2001 From: Adam Kariv Date: Thu, 8 Apr 2021 15:54:56 +0300 Subject: [PATCH 4/4] lint --- src/browser/renderer/DecorationRenderLayer.ts | 2 +- src/browser/renderer/Renderer.ts | 4 ++-- src/browser/services/Services.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/browser/renderer/DecorationRenderLayer.ts b/src/browser/renderer/DecorationRenderLayer.ts index 2561188218..f5281d729a 100644 --- a/src/browser/renderer/DecorationRenderLayer.ts +++ b/src/browser/renderer/DecorationRenderLayer.ts @@ -21,7 +21,7 @@ export class DecorationRenderLayer extends BaseRenderLayer { rendererId: number, @IDecorationService decorationService: IDecorationService, @IBufferService bufferService: IBufferService, - @IOptionsService optionsService: IOptionsService, + @IOptionsService optionsService: IOptionsService ) { super(container, 'decorations', zIndex, true, colors, rendererId, bufferService, optionsService); this._decorationService = decorationService; diff --git a/src/browser/renderer/Renderer.ts b/src/browser/renderer/Renderer.ts index 89eb00eb9a..075a07692d 100644 --- a/src/browser/renderer/Renderer.ts +++ b/src/browser/renderer/Renderer.ts @@ -37,7 +37,7 @@ export class Renderer extends Disposable implements IRenderer { @IInstantiationService instantiationService: IInstantiationService, @IBufferService private readonly _bufferService: IBufferService, @ICharSizeService private readonly _charSizeService: ICharSizeService, - @IOptionsService private readonly _optionsService: IOptionsService, + @IOptionsService private readonly _optionsService: IOptionsService ) { super(); const allowTransparency = this._optionsService.options.allowTransparency; @@ -46,7 +46,7 @@ export class Renderer extends Disposable implements IRenderer { instantiationService.createInstance(SelectionRenderLayer, this._screenElement, 1, this._colors, this._id), instantiationService.createInstance(LinkRenderLayer, this._screenElement, 2, this._colors, this._id, linkifier, linkifier2), instantiationService.createInstance(DecorationRenderLayer, this._screenElement, 3, this._colors, this._id), - instantiationService.createInstance(CursorRenderLayer, this._screenElement, 4, this._colors, this._id, this._onRequestRedraw), + instantiationService.createInstance(CursorRenderLayer, this._screenElement, 4, this._colors, this._id, this._onRequestRedraw) ]; this.dimensions = { scaledCharWidth: 0, diff --git a/src/browser/services/Services.ts b/src/browser/services/Services.ts index 11cb70110e..65147d79ac 100644 --- a/src/browser/services/Services.ts +++ b/src/browser/services/Services.ts @@ -119,6 +119,6 @@ export interface IDecorationService { addDecoration(element: IDecorationElement): IDecorationHandle; removeDeoration(handle: IDecorationHandle): boolean; - forEachDecoration(callback: (decoration: IDecorationElement) => boolean) : void; + forEachDecoration(callback: (decoration: IDecorationElement) => boolean): void; clearDecorations(): number; }