From bf41eb4204ef8b2d70c3ce001985d88774747a22 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:14:49 -0700 Subject: [PATCH] Add top/bottom border overview ruler options --- addons/addon-fit/src/FitAddon.ts | 2 +- demo/client.ts | 6 ++- src/browser/CoreBrowserTerminal.ts | 6 +-- src/browser/Viewport.ts | 4 +- .../decorations/OverviewRulerRenderer.ts | 10 ++++- src/common/services/OptionsService.ts | 2 +- src/common/services/Services.ts | 4 +- test/playwright/Terminal.test.ts | 2 +- typings/xterm.d.ts | 37 +++++++++++++++---- 9 files changed, 51 insertions(+), 22 deletions(-) diff --git a/addons/addon-fit/src/FitAddon.ts b/addons/addon-fit/src/FitAddon.ts index 283af354..a282ed3f 100644 --- a/addons/addon-fit/src/FitAddon.ts +++ b/addons/addon-fit/src/FitAddon.ts @@ -67,7 +67,7 @@ export class FitAddon implements ITerminalAddon , IFitApi { const scrollbarWidth = (this._terminal.options.scrollback === 0 ? 0 - : (this._terminal.options.overviewRulerWidth || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH)); + : (this._terminal.options.overviewRuler?.width || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH)); const parentElementStyle = window.getComputedStyle(this._terminal.element.parentElement); const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')); diff --git a/demo/client.ts b/demo/client.ts index 152b94cc..63fddc87 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -427,8 +427,10 @@ function initOptions(term: Terminal): void { 'termName', 'cols', 'rows', // subsumed by "size" (colsRows) option // Complex option + 'documentOverride', 'linkHandler', 'logger', + 'overviewRuler', 'theme', 'windowOptions', 'windowsPty', @@ -1159,7 +1161,7 @@ function addGraphemeClusters(): void { } function addDecoration(): void { - term.options['overviewRulerWidth'] = 15; + term.options['overviewRuler'] = { width: 14 }; const marker = term.registerMarker(1); const decoration = term.registerDecoration({ marker, @@ -1174,7 +1176,7 @@ function addDecoration(): void { } function addOverviewRuler(): void { - term.options['overviewRulerWidth'] = 15; + term.options['overviewRuler'] = { width: 14 }; term.registerDecoration({ marker: term.registerMarker(1), overviewRulerOptions: { color: '#ef2929' } }); term.registerDecoration({ marker: term.registerMarker(3), overviewRulerOptions: { color: '#8ae234' } }); term.registerDecoration({ marker: term.registerMarker(5), overviewRulerOptions: { color: '#729fcf' } }); diff --git a/src/browser/CoreBrowserTerminal.ts b/src/browser/CoreBrowserTerminal.ts index 235cb79f..ee8405eb 100644 --- a/src/browser/CoreBrowserTerminal.ts +++ b/src/browser/CoreBrowserTerminal.ts @@ -549,11 +549,11 @@ export class CoreBrowserTerminal extends CoreTerminal implements ITerminal { } this.register(this.optionsService.onSpecificOptionChange('screenReaderMode', e => this._handleScreenReaderModeOptionChange(e))); - if (this.options.overviewRulerWidth) { + if (this.options.overviewRuler.width) { this._overviewRulerRenderer = this.register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement)); } - this.optionsService.onSpecificOptionChange('overviewRulerWidth', value => { - if (!this._overviewRulerRenderer && value && this._viewportElement && this.screenElement) { + this.optionsService.onSpecificOptionChange('overviewRuler', value => { + if (!this._overviewRulerRenderer && value.width && this._viewportElement && this.screenElement) { this._overviewRulerRenderer = this.register(this._instantiationService.createInstance(OverviewRulerRenderer, this._viewportElement, this.screenElement)); } }); diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 221420a2..9543cf1e 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -60,7 +60,7 @@ export class Viewport extends Disposable { this.register(this._optionsService.onMultipleOptionChange([ 'scrollSensitivity', 'fastScrollSensitivity', - 'overviewRulerWidth' + 'overviewRuler' ], () => this._scrollableElement.updateOptions(this._getChangeOptions()))); // Don't handle mouse wheel if wheel events are supported by the current mouse prototcol this.register(coreMouseService.onProtocolChange(type => { @@ -121,7 +121,7 @@ export class Viewport extends Disposable { return { mouseWheelScrollSensitivity: this._optionsService.rawOptions.scrollSensitivity, fastScrollSensitivity: this._optionsService.rawOptions.fastScrollSensitivity, - verticalScrollbarSize: this._optionsService.rawOptions.overviewRulerWidth || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH + verticalScrollbarSize: this._optionsService.rawOptions.overviewRuler?.width || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH }; } diff --git a/src/browser/decorations/OverviewRulerRenderer.ts b/src/browser/decorations/OverviewRulerRenderer.ts index 80095222..2598e888 100644 --- a/src/browser/decorations/OverviewRulerRenderer.ts +++ b/src/browser/decorations/OverviewRulerRenderer.ts @@ -38,7 +38,7 @@ export class OverviewRulerRenderer extends Disposable { private readonly _ctx: CanvasRenderingContext2D; private readonly _colorZoneStore: IColorZoneStore = new ColorZoneStore(); private get _width(): number { - return this._optionsService.options.overviewRulerWidth || 0; + return this._optionsService.options.overviewRuler?.width || 0; } private _animationFrame: number | undefined; @@ -95,7 +95,7 @@ export class OverviewRulerRenderer extends Disposable { })); this.register(this._coreBrowserService.onDprChange(() => this._queueRefresh(true))); - this.register(this._optionsService.onSpecificOptionChange('overviewRulerWidth', () => this._queueRefresh(true))); + this.register(this._optionsService.onSpecificOptionChange('overviewRuler', () => this._queueRefresh(true))); this.register(this._themeService.onChangeColors(() => this._queueRefresh())); this._queueRefresh(true); } @@ -176,6 +176,12 @@ export class OverviewRulerRenderer extends Disposable { private _renderRulerOutline(): void { this._ctx.fillStyle = this._themeService.colors.overviewRulerBorder.css; this._ctx.fillRect(0, 0, Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.height); + if (this._optionsService.rawOptions.overviewRuler.showTopBorder) { + this._ctx.fillRect(Constants.OVERVIEW_RULER_BORDER_WIDTH, 0, this._canvas.width - Constants.OVERVIEW_RULER_BORDER_WIDTH, Constants.OVERVIEW_RULER_BORDER_WIDTH); + } + if (this._optionsService.rawOptions.overviewRuler.showBottomBorder) { + this._ctx.fillRect(Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.height - Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.width - Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.height); + } } private _renderColorZone(zone: IColorZone): void { diff --git a/src/common/services/OptionsService.ts b/src/common/services/OptionsService.ts index 5a3da107..99573b8c 100644 --- a/src/common/services/OptionsService.ts +++ b/src/common/services/OptionsService.ts @@ -54,7 +54,7 @@ export const DEFAULT_OPTIONS: Readonly> = { convertEol: false, termName: 'xterm', cancelEvents: false, - overviewRulerWidth: 0 + overviewRuler: {} }; const FONT_WEIGHT_OPTIONS: Extract[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900']; diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index d677556c..0ceff36c 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IDecoration, IDecorationOptions, ILinkHandler, ILogger, IWindowsPty } from '@xterm/xterm'; +import { IDecoration, IDecorationOptions, ILinkHandler, ILogger, IWindowsPty, type IOverviewRulerOptions } from '@xterm/xterm'; import { CoreMouseEncoding, CoreMouseEventType, CursorInactiveStyle, CursorStyle, IAttributeData, ICharset, IColor, ICoreMouseEvent, ICoreMouseProtocol, IDecPrivateModes, IDisposable, IModes, IOscLinkData, IWindowOptions } from 'common/Types'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; import { createDecorator } from 'common/services/ServiceRegistry'; @@ -251,7 +251,7 @@ export interface ITerminalOptions { windowsPty?: IWindowsPty; windowOptions?: IWindowOptions; wordSeparator?: string; - overviewRulerWidth?: number; + overviewRuler?: IOverviewRulerOptions; [key: string]: any; cancelEvents: boolean; diff --git a/test/playwright/Terminal.test.ts b/test/playwright/Terminal.test.ts index 19f6eb31..aea90cdf 100644 --- a/test/playwright/Terminal.test.ts +++ b/test/playwright/Terminal.test.ts @@ -760,7 +760,7 @@ test.describe('API Integration Tests', () => { await pollFor(ctx.page, `document.querySelectorAll('.xterm-decoration-overview-ruler').length`, 0); }); test('should add an overview ruler when width is set', async () => { - await openTerminal(ctx, { overviewRulerWidth: 15 }); + await openTerminal(ctx, { overviewRuler: { width: 15 } }); await ctx.page.evaluate(`window.marker1 = window.term.registerMarker(1)`); await ctx.page.evaluate(`window.marker2 = window.term.registerMarker(2)`); await ctx.page.evaluate(`window.term.registerDecoration({ marker: window.marker1, overviewRulerOptions: { color: 'red', position: 'full' } })`); diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index af73230a..f9cf14f9 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -327,10 +327,10 @@ declare module '@xterm/xterm' { windowOptions?: IWindowOptions; /** - * The width, in pixels, of the canvas for the overview ruler. The overview - * ruler will be hidden when not set. + * Controls the visibility and style of the overview ruler which visualizes + * decorations underneath the scroll bar. */ - overviewRulerWidth?: number; + overviewRuler?: IOverviewRulerOptions; } /** @@ -387,9 +387,8 @@ declare module '@xterm/xterm' { scrollbarSliderActiveBackground?: string; /** * The border color of the overview ruler. This visually separates the - * terminal from the scroll bar when - * {@link ITerminalOptions.overviewRulerWidth overviewRulerWidth} is set. - * When this is not set it defaults to black (`#000000`). + * terminal from the scroll bar when {@link IOverviewRulerOptions.width} is + * set. When this is not set it defaults to black (`#000000`). */ overviewRulerBorder?: string; /** ANSI black (eg. `\x1b[30m`) */ @@ -617,8 +616,8 @@ declare module '@xterm/xterm' { /** * When defined, renders the decoration in the overview ruler to the right - * of the terminal. {@link ITerminalOptions.overviewRulerWidth} must be set - * in order to see the overview ruler. + * of the terminal. {@link IOverviewRulerOptions.width} must be set in order + * to see the overview ruler. * @param color The color of the decoration. * @param position The position of the decoration. */ @@ -641,6 +640,28 @@ declare module '@xterm/xterm' { tooMuchOutput: string; } + export interface IOverviewRulerOptions { + /** + * When defined, renders decorations in the overview ruler to the right of + * the terminal. This must be set in order to see the overview ruler. + * @param color The color of the decoration. + * @param position The position of the decoration. + */ + width?: number; + + /** + * Whether to show the top border of the overview ruler, which uses the + * {@link ITheme.overviewRulerBorder} color. + */ + showTopBorder?: boolean; + + /** + * Whether to show the bottom border of the overview ruler, which uses the + * {@link ITheme.overviewRulerBorder} color. + */ + showBottomBorder?: boolean; + } + /** * Enable various window manipulation and report features * (`CSI Ps ; Ps ; Ps t`).