diff --git a/addons/xterm-addon-ligatures/yarn.lock b/addons/xterm-addon-ligatures/yarn.lock index ef052e86..64117742 100644 --- a/addons/xterm-addon-ligatures/yarn.lock +++ b/addons/xterm-addon-ligatures/yarn.lock @@ -67,9 +67,9 @@ fd-slicer@~1.1.0: pend "~1.2.0" follow-redirects@^1.14.0: - version "1.14.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" - integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== font-finder@^1.0.3: version "1.0.4" diff --git a/src/browser/services/DecorationService.ts b/src/browser/services/DecorationService.ts index f29ec7ea..957a5de5 100644 --- a/src/browser/services/DecorationService.ts +++ b/src/browser/services/DecorationService.ts @@ -16,11 +16,7 @@ export class DecorationService extends Disposable implements IDecorationService private _screenElement: HTMLElement | undefined; private _renderService: IRenderService | undefined; - constructor( - @IBufferService private readonly _bufferService: IBufferService, - @IInstantiationService private readonly _instantiationService: IInstantiationService) { - super(); - } + constructor(@IInstantiationService private readonly _instantiationService: IInstantiationService) { super(); } public attachToDom(screenElement: HTMLElement, renderService: IRenderService): void { this._renderService = renderService; @@ -28,7 +24,6 @@ export class DecorationService extends Disposable implements IDecorationService 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))); } @@ -43,12 +38,12 @@ export class DecorationService extends Disposable implements IDecorationService return decoration; } - public refresh(recreate?: boolean): void { - if (!this._bufferService || !this._renderService) { + public refresh(shouldRecreate?: boolean): void { + if (!this._renderService) { return; } for (const decoration of this._decorations) { - decoration.render(this._renderService, recreate); + decoration.render(this._renderService, shouldRecreate); } } @@ -56,16 +51,15 @@ export class DecorationService extends Disposable implements IDecorationService for (const decoration of this._decorations) { decoration.dispose(); } - if (this._container) { - this._screenElement?.removeChild(this._container); + if (this._screenElement && this._container && this._screenElement.contains(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; } @@ -90,48 +84,56 @@ export class Decoration extends Disposable implements IDecoration { super(); this.x = options.x ?? 0; this._marker = options.marker; + this._marker.onDispose(() => this.dispose()); 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); + public render(renderService: IRenderService, shouldRecreate?: boolean): void { + if (!this._element || shouldRecreate) { + this._createElement(renderService, shouldRecreate); } if (this._container && this._element && !this._container.contains(this._element)) { this._container.append(this._element); } this._refreshStyle(renderService); - this._onRender.fire(this._element!); + if (this._element) { + this._onRender.fire(this._element); + } } - private _createElement(renderService: IRenderService, recreate?: boolean): void { - if (recreate && this._element) { + private _createElement(renderService: IRenderService, shouldRecreate?: boolean): void { + if (shouldRecreate && this._element && this._container.contains(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`; + this._element.style.width = `${this.width * renderService.dimensions.actualCellWidth}px`; + this._element.style.height = `${this.height * renderService.dimensions.actualCellHeight}px`; + this._element.style.top = `${(this.marker.line - this._bufferService.buffers.active.ydisp) * renderService.dimensions.actualCellHeight}px`; if (this.x && this.x > this._bufferService.cols) { - this._element!.style.display = 'none'; + // exceeded the container width, so hide + this._element.style.display = 'none'; } if (this.anchor === 'right') { - this._element.style.right = this.x ? `${this.x * renderService.dimensions.scaledCellWidth}px` : ''; + this._element.style.right = this.x ? `${this.x * renderService.dimensions.actualCellWidth}px` : ''; } else { - this._element.style.left = this.x ? `${this.x * renderService.dimensions.scaledCellWidth}px` : ''; + this._element.style.left = this.x ? `${this.x * renderService.dimensions.actualCellWidth}px` : ''; } this.register({ dispose: () => { if (this.isDisposed) { return; } - this._container.removeChild(this._element!); + if (!this.marker.isDisposed) { + this.marker.dispose(); + } + if (this._element && this._container.contains(this._element)) { + 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(); @@ -140,13 +142,16 @@ export class Decoration extends Disposable implements IDecoration { } private _refreshStyle(renderService: IRenderService): void { + if (!this._element) { + return; + } 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'; + this._element.style.display = 'none'; } else { - this._element!.style.top = `${line * renderService.dimensions.scaledCellHeight}px`; - this._element!.style.display = 'block'; + this._element.style.top = `${line * renderService.dimensions.actualCellHeight}px`; + this._element.style.display = this._bufferService.buffer === this._bufferService.buffers.alt ? 'none' : 'block'; } } } diff --git a/src/common/InputHandler.ts b/src/common/InputHandler.ts index 88634048..6198aa37 100644 --- a/src/common/InputHandler.ts +++ b/src/common/InputHandler.ts @@ -1232,6 +1232,7 @@ export class InputHandler extends Disposable implements IInputHandler { const line = this._activeBuffer.lines.get(this._activeBuffer.ybase + y)!; line.fill(this._activeBuffer.getNullCell(this._eraseAttrData())); line.isWrapped = false; + this._bufferService.buffer.clearMarkers(y); } /** diff --git a/src/common/buffer/Buffer.ts b/src/common/buffer/Buffer.ts index 8addf45a..266c16aa 100644 --- a/src/common/buffer/Buffer.ts +++ b/src/common/buffer/Buffer.ts @@ -585,12 +585,19 @@ export class Buffer implements IBuffer { return x >= this._cols ? this._cols - 1 : x < 0 ? 0 : x; } - public clearMarkers(): void { + public clearMarkers(y?: number): void { this._isClearing = true; - for (const marker of this.markers) { - marker.dispose(); + if (y) { + for (const marker of this.markers.filter(m => m.line === y)) { + marker.dispose(); + this.markers.splice(this.markers.indexOf(marker), 1); + } + } else { + for (const marker of this.markers) { + marker.dispose(); + } + this.markers = []; } - this.markers = []; this._isClearing = false; } diff --git a/src/common/buffer/Types.d.ts b/src/common/buffer/Types.d.ts index 9259d46d..36b70b7f 100644 --- a/src/common/buffer/Types.d.ts +++ b/src/common/buffer/Types.d.ts @@ -45,7 +45,7 @@ export interface IBuffer { getNullCell(attr?: IAttributeData): ICellData; getWhitespaceCell(attr?: IAttributeData): ICellData; addMarker(y: number): IMarker; - clearMarkers(): void; + clearMarkers(y?: number): void; } export interface IBufferSet extends IDisposable {