mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
get it working in demo with overviewRulerwidth not considered"
This commit is contained in:
+3
-1
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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'];
|
||||
|
||||
Vendored
+11
-6
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user