diff --git a/src/browser/Linkifier2.test.ts b/src/browser/Linkifier2.test.ts index 36a6da43..fb71b6aa 100644 --- a/src/browser/Linkifier2.test.ts +++ b/src/browser/Linkifier2.test.ts @@ -10,6 +10,14 @@ import { MockBufferService } from 'common/TestUtils.test'; import { ILink } from 'browser/Types'; class TestLinkifier2 extends Linkifier2 { + protected _currentLinkState = { + decorations: { + underline: true, + pointerCursor: true + }, + isHovered: true + }; + constructor(bufferService: IBufferService) { super(bufferService); } @@ -47,7 +55,7 @@ describe('Linkifier2', () => { activate: () => { } }; - it('onLinkHover event range is correct', done => { + it('onShowLinkUnderline event range is correct', done => { linkifier.onShowLinkUnderline(e => { assert.equal(link.range.start.x - 1, e.x1); assert.equal(link.range.start.y - 1, e.y1); @@ -60,7 +68,7 @@ describe('Linkifier2', () => { linkifier.linkHover({ classList: { add: () => { } } } as any, link, {} as any); }); - it('onLinkLeave event range is correct', done => { + it('onHideLinkUnderline event range is correct', done => { linkifier.onHideLinkUnderline(e => { assert.equal(link.range.start.x - 1, e.x1); assert.equal(link.range.start.y - 1, e.y1); diff --git a/src/browser/Linkifier2.ts b/src/browser/Linkifier2.ts index 8b8e2894..a21f7621 100644 --- a/src/browser/Linkifier2.ts +++ b/src/browser/Linkifier2.ts @@ -3,14 +3,14 @@ * @license MIT */ -import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent } from './Types'; +import { ILinkifier2, ILinkProvider, IBufferCellPosition, ILink, ILinkifierEvent, ILinkDecorations } from './Types'; import { IDisposable } from 'common/Types'; import { IMouseService, IRenderService } from './services/Services'; import { IBufferService } from 'common/services/Services'; import { EventEmitter, IEvent } from 'common/EventEmitter'; interface ILinkState { - hideDecorations: boolean; + decorations: ILinkDecorations; isHovered: boolean; } @@ -20,7 +20,7 @@ export class Linkifier2 implements ILinkifier2 { private _renderService: IRenderService | undefined; private _linkProviders: ILinkProvider[] = []; private _currentLink: ILink | undefined; - private _currentLinkState: ILinkState | undefined; + protected _currentLinkState: ILinkState | undefined; private _lastMouseEvent: MouseEvent | undefined; private _linkCacheDisposables: IDisposable[] = []; private _lastBufferCell: IBufferCellPosition | undefined; @@ -199,21 +199,35 @@ export class Linkifier2 implements ILinkifier2 { if (this._linkAtPosition(link, position)) { this._currentLink = link; this._currentLinkState = { - hideDecorations: link.hideDecorations || false, + decorations: { + underline: link.decorations === undefined ? true : link.decorations.underline, + pointerCursor: link.decorations === undefined ? true : link.decorations.pointerCursor + }, isHovered: true }; this._linkHover(this._element, link, this._lastMouseEvent); - // Add listener for tracking hideDecorations changes - Object.defineProperties(link, { - hideDecorations: { - get: () => this._currentLinkState?.hideDecorations, + // Add listener for tracking decorations changes + link.decorations = {} as ILinkDecorations; + Object.defineProperties(link.decorations, { + pointerCursor: { + get: () => this._currentLinkState?.decorations.pointerCursor, set: v => { - if (this._currentLinkState && this._currentLinkState.hideDecorations !== v) { - this._currentLinkState.hideDecorations = v; - if (this._currentLinkState?.isHovered) { - this._fireUnderlineEvent(link, !v); - this._element?.classList.toggle('xterm-cursor-pointer', !v); + if (this._currentLinkState && this._currentLinkState?.decorations.pointerCursor !== v) { + this._currentLinkState.decorations.pointerCursor = v; + if (this._currentLinkState.isHovered) { + this._element?.classList.toggle('xterm-cursor-pointer', v); + } + } + } + }, + underline: { + get: () => this._currentLinkState?.decorations.underline, + set: v => { + if (this._currentLinkState && this._currentLinkState?.decorations.underline !== v) { + this._currentLinkState.decorations.underline = v; + if (this._currentLinkState.isHovered) { + this._fireUnderlineEvent(link, v); } } } @@ -230,12 +244,14 @@ export class Linkifier2 implements ILinkifier2 { } protected _linkHover(element: HTMLElement, link: ILink, event: MouseEvent): void { - if (!link.hideDecorations) { - this._fireUnderlineEvent(link, true); - element.classList.add('xterm-cursor-pointer'); - } if (this._currentLinkState) { this._currentLinkState.isHovered = true; + if (this._currentLinkState.decorations.underline) { + this._fireUnderlineEvent(link, true); + } + if (this._currentLinkState.decorations.pointerCursor) { + element.classList.add('xterm-cursor-pointer'); + } } if (link.hover) { @@ -252,12 +268,14 @@ export class Linkifier2 implements ILinkifier2 { } protected _linkLeave(element: HTMLElement, link: ILink, event: MouseEvent): void { - if (!link.hideDecorations) { - this._fireUnderlineEvent(link, false); - element.classList.remove('xterm-cursor-pointer'); - } if (this._currentLinkState) { this._currentLinkState.isHovered = false; + if (this._currentLinkState.decorations.underline) { + this._fireUnderlineEvent(link, false); + } + if (this._currentLinkState.decorations.pointerCursor) { + element.classList.remove('xterm-cursor-pointer'); + } } if (link.leave) { diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index 382d1c42..f4645543 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -172,12 +172,17 @@ interface ILinkProvider { interface ILink { range: IBufferRange; text: string; - hideDecorations?: boolean; + decorations?: ILinkDecorations; activate(event: MouseEvent, text: string): void; hover?(event: MouseEvent, text: string): void; leave?(event: MouseEvent, text: string): void; } +interface ILinkDecorations { + pointerCursor: boolean; + underline: boolean; +} + interface IBufferRange { start: IBufferCellPosition; end: IBufferCellPosition; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index c8901176..3487c410 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -1121,10 +1121,11 @@ declare module 'xterm' { text: string; /** - * Whether to hide the underline and cursor styles, this property is tracked and changes made - * after the link is provided will trigger changes. + * What link decorations to show when hovering the link, this property is tracked and changes + * made after the link is provided will trigger changes. If not set, all decroations will be + * enabled. */ - hideDecorations?: boolean; + decorations?: ILinkDecorations; /** * Calls when the link is activated. @@ -1150,6 +1151,21 @@ declare module 'xterm' { leave?(event: MouseEvent, text: string): void; } + /** + * A set of decorations that can be applied to links. + */ + interface ILinkDecorations { + /** + * Whether the cursor is set to pointer. + */ + pointerCursor: boolean; + + /** + * Whether the underline is visible + */ + underline: boolean; + } + /** * A range within a buffer. */