get it working in demo with overviewRulerwidth not considered"

This commit is contained in:
meganrogge
2022-03-15 10:27:01 -04:00
parent bfb048110f
commit 079bbc8242
5 changed files with 88 additions and 113 deletions
+3 -1
View File
@@ -554,8 +554,10 @@ function addDecoration() {
function addOverviewRuler() {
const canvas = term.registerDecoration({marker: term.addMarker(1), overviewRulerItemColor: 'red'});
canvas.element!.style.left = `${document.querySelector('.xterm-viewport').clientWidth + 5}px`;
term.registerDecoration({marker: term.addMarker(3), overviewRulerItemColor: 'green'});
term.registerDecoration({marker: term.addMarker(5), overviewRulerItemColor: 'blue'});
canvas.onRender((e) => {
e.style.left = `${document.querySelector('.xterm-viewport').clientWidth + 5}px`;
});
}
@@ -5,36 +5,37 @@
import { addDisposableDomListener } from 'browser/Lifecycle';
import { IRenderService } from 'browser/services/Services';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { Disposable } from 'common/Lifecycle';
import { IBufferService, IDecorationService, IInstantiationService, IInternalDecoration } from 'common/services/Services';
import { IDecorationOptions, IDecoration, IMarker } from 'xterm';
import { IBufferService, IDecorationService, IInternalDecoration, IOptionsService } from 'common/services/Services';
const enum ScrollbarConstants {
WIDTH = 7
WIDTH = 15
}
export class OverviewRulerRenderer extends Disposable {
private _canvas: HTMLCanvasElement;
private _ctx: CanvasRenderingContext2D | null;
private _decorations: ScrollbarDecoration[] = [];
private _width: number | undefined;
private _anchor: 'right' | 'left' | undefined;
private _x: number | undefined;
private readonly _decorationElements: Map<IInternalDecoration, HTMLElement> = new Map();
private _animationFrame: number | undefined;
constructor(
private readonly _viewportElement: HTMLElement,
private readonly _screenElement: HTMLElement,
@IBufferService private readonly _bufferService: IBufferService,
@IDecorationService private readonly _decorationService: IDecorationService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IRenderService private readonly _renderService: IRenderService
@IRenderService private readonly _renderService: IRenderService,
@IOptionsService private readonly _optionsService: IOptionsService
) {
super();
this._canvas = document.createElement('canvas');
this._canvas.classList.add('xterm-decoration-scrollbar');
this._viewportElement.parentElement?.insertBefore(this._canvas, this._viewportElement);
this._ctx = this._canvas.getContext('2d');
this._canvas.style.width = `${this._optionsService.options.overviewRulerWidth || ScrollbarConstants.WIDTH}px`;
this._canvas.style.height = `${this._screenElement.clientHeight}px`;
this._canvas.width = Math.floor((this._optionsService.options.overviewRulerWidth|| ScrollbarConstants.WIDTH)* window.devicePixelRatio);
this._canvas.height = Math.floor(this._screenElement.clientHeight * window.devicePixelRatio);
this.refreshDecorations();
this.register(this._bufferService.buffers.onBufferActivate(() => {
this._canvas!.style.display = this._bufferService.buffer === this._bufferService.buffers.alt ? 'none' : 'block';
@@ -42,111 +43,80 @@ export class OverviewRulerRenderer extends Disposable {
this.register(this._renderService.onRenderedBufferChange(() => this.refreshDecorations()));
this.register(this._renderService.onDimensionsChange(() => this.refreshDecorations()));
this.register(addDisposableDomListener(window, 'resize', () => this.refreshDecorations()));
this.register(this._decorationService.onDecorationRegistered(e => this.registerDecoration(e)));
this.register(this._decorationService.onDecorationRemoved(d => d.dispose()));
this.register(this._decorationService.onDecorationRegistered(() => this._queueRefresh()));
this.register(this._decorationService.onDecorationRemoved(decoration => this._removeDecoration(decoration)));
}
public registerDecoration(decoration: IInternalDecoration): void {
if (!this._ctx || !decoration.options.overviewRulerItemColor) {
public override dispose(): void {
for (const decoration of this._decorationElements) {
this._ctx?.clearRect(
0,
Math.round(this._canvas.height * (decoration[0].marker.line / this._bufferService.buffers.active.lines.length)),
this._canvas.width,
window.devicePixelRatio
);
}
this._decorationElements.clear();
this._canvas?.remove();
super.dispose();
}
private _refreshStyle(decoration: IInternalDecoration): void {
if (!this._ctx) {
return;
}
if (decoration.options.anchor === 'right') {
this._canvas.style.right = decoration.options.x ? `${decoration.options.x * this._renderService.dimensions.actualCellWidth}px` : '';
} else {
this._canvas.style.left = decoration.options.x ? `${decoration.options.x * this._renderService.dimensions.actualCellWidth}px` : '';
}
if (!decoration.options.overviewRulerItemColor) {
this._decorationElements.delete(decoration);
return;
}
// TODO: Does this do anything anymore?
this._instantiationService.createInstance(ScrollbarDecoration, { marker: decoration.options.marker, overviewRulerItemColor: decoration.options.overviewRulerItemColor });
this._ctx.lineWidth = 1;
this._ctx.strokeStyle = decoration.options.overviewRulerItemColor;
this._ctx.strokeRect(
0,
Math.round(this._canvas.height * (decoration.marker.line / this._bufferService.buffers.active.lines.length)),
Math.round(this._canvas.height * (decoration.options.marker.line / this._bufferService.buffers.active.lines.length)),
this._canvas.width,
window.devicePixelRatio
);
}
public refreshDecorations(): void {
if (!this._ctx) {
return;
}
this._canvas.style.width = `${this._width || ScrollbarConstants.WIDTH}px`;
this._canvas.style.width = `${this._canvas.width || ScrollbarConstants.WIDTH}px`;
this._canvas.style.height = `${this._screenElement.clientHeight}px`;
this._canvas.width = Math.floor((this._width || ScrollbarConstants.WIDTH)* window.devicePixelRatio);
this._canvas.width = Math.floor((this._canvas.width || ScrollbarConstants.WIDTH)* window.devicePixelRatio);
this._canvas.height = Math.floor(this._screenElement.clientHeight * window.devicePixelRatio);
if (this._anchor === 'right') {
this._canvas.style.right = this._x ? `${this._x * this._renderService.dimensions.actualCellWidth}px` : '';
} else {
this._canvas.style.left = this._x ? `${this._x * this._renderService.dimensions.actualCellWidth}px` : '';
}
this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
for (const decoration of this._decorations) {
decoration.render(this._ctx, this._canvas);
for (const decoration of this._decorationService.decorations) {
this._renderDecoration(decoration);
}
}
public override dispose(): void {
for (const decoration of this._decorations) {
decoration.dispose();
private _renderDecoration(decoration: IInternalDecoration): void {
const element = this._decorationElements.get(decoration);
if (!element) {
this._decorationElements.set(decoration, this._canvas);
}
this._decorations = [];
this._canvas?.remove();
super.dispose();
}
}
class ScrollbarDecoration extends Disposable implements IDecoration {
private readonly _marker: IMarker;
private _ctx: CanvasRenderingContext2D | undefined;
private _canvas: HTMLCanvasElement | undefined;
private _color: string | undefined;
public isDisposed: boolean = false;
public get element(): HTMLCanvasElement | undefined { return this._canvas; }
public get marker(): IMarker { return this._marker; }
public get color(): string | undefined { return this._color; }
private _onDispose = new EventEmitter<void>();
public get onDispose(): IEvent<void> { return this._onDispose.event; }
private _onRender = new EventEmitter<HTMLElement>();
public get onRender(): IEvent<HTMLElement> { return this._onRender.event; }
constructor(
options: IDecorationOptions,
@IBufferService private readonly _bufferService: IBufferService
) {
super();
this._marker = options.marker;
this._color = options.overviewRulerItemColor;
this._marker.onDispose(() => this.dispose());
this._refreshStyle(decoration);
decoration.onRenderEmitter.fire(this._canvas);
}
public render(ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement): void {
if (!this.color) {
throw new Error('No color was provided for the overview ruler decoraiton');
}
this._ctx = ctx;
this._canvas = canvas;
ctx.lineWidth = 1;
ctx.strokeStyle = this.color;
ctx.strokeRect(
0,
Math.round(canvas.height * (this.marker.line / this._bufferService.buffers.active.lines.length)),
canvas.width,
window.devicePixelRatio
);
this._onRender.fire(canvas);
}
public override dispose(): void {
if (this._isDisposed || !this._canvas || !this._ctx) {
private _queueRefresh(): void {
if (this._animationFrame !== undefined) {
return;
}
this._ctx.clearRect(
0,
Math.round(this._canvas.height * (this.marker.line / this._bufferService.buffers.active.lines.length)),
this._canvas.width,
window.devicePixelRatio
);
this.isDisposed = true;
this._onDispose.fire();
super.dispose();
this._animationFrame = window.requestAnimationFrame(() => {
this.refreshDecorations();
this._animationFrame = undefined;
});
}
private _removeDecoration(decoration: IInternalDecoration): void {
const element = this._decorationElements.get(decoration);
element?.remove();
this._decorationElements.delete(decoration);
}
}
+8 -11
View File
@@ -75,7 +75,6 @@ export class Terminal extends CoreTerminal implements ITerminal {
private _compositionView: HTMLElement | undefined;
private _overviewRulerRenderer: OverviewRulerRenderer | undefined;
private _bufferDecorationRenderer: BufferDecorationRenderer | undefined;
// private _visualBellTimer: number;
@@ -587,16 +586,7 @@ export class Terminal extends CoreTerminal implements ITerminal {
this.register(this.onScroll(() => this._mouseZoneManager!.clearAll()));
this.linkifier.attachToDom(this.element, this._mouseZoneManager);
this.linkifier2.attachToDom(this.screenElement, this._mouseService, this._renderService);
if (this._decorationService) {
this._bufferDecorationRenderer = this._instantiationService.createInstance(BufferDecorationRenderer, this.screenElement);
}
if (this.options.overviewRulerWidth && this._decorationService) {
this._overviewRulerRenderer = this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement);
}
this.optionsService.onOptionChange(() => {
if (!this._overviewRulerRenderer && this.options.overviewRulerWidth && this._renderService && this._viewportElement && this.screenElement && this._decorationService) {
this._overviewRulerRenderer = this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement);
}});
this._instantiationService.createInstance(BufferDecorationRenderer, this.screenElement);
// This event listener must be registered aftre MouseZoneManager is created
this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this._selectionService!.onMouseDown(e)));
@@ -614,6 +604,13 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._accessibilityManager = new AccessibilityManager(this, this._renderService);
}
// if (this.options.overviewRulerWidth) {
this._overviewRulerRenderer = this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement);
// }
this.optionsService.onOptionChange(() => {
if (!this._overviewRulerRenderer && this.options.overviewRulerWidth && this._viewportElement && this.screenElement) {
this._overviewRulerRenderer = this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement);
}});
// Measure the character size
this._charSizeService.measure();
+2 -1
View File
@@ -52,7 +52,8 @@ export const DEFAULT_OPTIONS: Readonly<ITerminalOptions> = {
altClickMovesCursor: true,
convertEol: false,
termName: 'xterm',
cancelEvents: false
cancelEvents: false,
overviewRulerWidth: undefined
};
const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];
+11 -6
View File
@@ -266,6 +266,11 @@ declare module 'xterm' {
* All features are disabled by default for security reasons.
*/
windowOptions?: IWindowOptions;
/**
* The width, in pixels, of the canvas for the overview ruler.
*/
overviewRulerWidth?: number;
}
/**
@@ -394,7 +399,7 @@ declare module 'xterm' {
}
/**
* Represents a disposable with an
* Represents a disposable with an
* @param onDispose event listener and
* @param isDisposed property.
*/
@@ -436,7 +441,7 @@ declare module 'xterm' {
/**
* Options provided when registering a decoration
* containing a @param marker, @param anchor,
* containing a @param marker, @param anchor,
* @param x offset from the anchor, @param width in cells
* and @param height in cells.
*/
@@ -455,19 +460,19 @@ declare module 'xterm' {
/**
* The x position offset relative to the anchor
*/
*/
x?: number;
/**
* The width of the decoration in cells, which defaults to
* The width of the decoration in cells, which defaults to
* cell width or the width in pixels, when an overlayRulerItemColor
* is provided.
*/
width?: number;
/**
* The height of the decoration in cells, which defaults to
* The height of the decoration in cells, which defaults to
* cell height
*/
height?: number;
@@ -946,7 +951,7 @@ declare module 'xterm' {
/**
* (EXPERIMENTAL) Adds a decoration to the terminal using
* @param decorationOptions, which takes a marker and an optional anchor,
* @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.