From 1ffa568a2fe16ae7d87e4ba6a7dc324390467594 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 13 Jul 2019 13:47:17 -0700 Subject: [PATCH] Remove ITerminal from Linkifier --- src/Linkifier.test.ts | 49 +++++++++++++++++++++---------------------- src/Linkifier.ts | 47 ++++++++++++++++++++++------------------- src/Terminal.ts | 6 ++---- src/Types.d.ts | 2 +- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Linkifier.test.ts b/src/Linkifier.test.ts index ac1fb8b3..973e6d9b 100644 --- a/src/Linkifier.test.ts +++ b/src/Linkifier.test.ts @@ -4,23 +4,23 @@ */ import { assert } from 'chai'; -import { IMouseZoneManager, IMouseZone, ILinkMatcher, ITerminal } from './Types'; +import { IMouseZoneManager, IMouseZone, ILinkMatcher } from './Types'; import { IBufferLine } from 'common/Types'; import { Linkifier } from './Linkifier'; -import { MockBuffer, MockTerminal, TestTerminal } from './TestUtils.test'; -import { CircularList } from 'common/CircularList'; +import { TestTerminal } from './TestUtils.test'; import { BufferLine } from 'common/buffer/BufferLine'; import { CellData } from 'common/buffer/CellData'; -import { MockLogService } from 'common/TestUtils.test'; +import { MockLogService, MockBufferService } from 'common/TestUtils.test'; +import { IBufferService } from 'common/services/Services'; class TestLinkifier extends Linkifier { - constructor(terminal: ITerminal) { - super(terminal, new MockLogService()); + constructor(bufferService: IBufferService) { + super(bufferService, new MockLogService()); Linkifier._timeBeforeLatency = 0; } public get linkMatchers(): ILinkMatcher[] { return this._linkMatchers; } - public linkifyRows(): void { super.linkifyRows(0, this._terminal.buffer.lines.length - 1); } + public linkifyRows(): void { super.linkifyRows(0, this._bufferService.buffer.lines.length - 1); } } class TestMouseZoneManager implements IMouseZoneManager { @@ -37,18 +37,13 @@ class TestMouseZoneManager implements IMouseZoneManager { } describe('Linkifier', () => { - let terminal: ITerminal; + let bufferService: IBufferService; let linkifier: TestLinkifier; let mouseZoneManager: TestMouseZoneManager; beforeEach(() => { - terminal = new MockTerminal(); - (terminal as any).cols = 100; - (terminal as any).rows = 10; - terminal.buffer = new MockBuffer(); - (terminal.buffer).setLines(new CircularList(20)); - terminal.buffer.ydisp = 0; - linkifier = new TestLinkifier(terminal); + bufferService = new MockBufferService(100, 10); + linkifier = new TestLinkifier(bufferService); mouseZoneManager = new TestMouseZoneManager(); }); @@ -61,13 +56,12 @@ describe('Linkifier', () => { } function addRow(text: string): void { - terminal.buffer.lines.push(stringToRow(text)); + bufferService.buffer.lines.push(stringToRow(text)); } function assertLinkifiesRow(rowText: string, linkMatcherRegex: RegExp, links: {x: number, length: number}[], done: MochaDone): void { addRow(rowText); linkifier.registerLinkMatcher(linkMatcherRegex, () => {}); - (terminal as any).rows = terminal.buffer.lines.length - 1; linkifier.linkifyRows(); // Allow linkify to happen setTimeout(() => { @@ -75,8 +69,8 @@ describe('Linkifier', () => { links.forEach((l, i) => { assert.equal(mouseZoneManager.zones[i].x1, l.x + 1); assert.equal(mouseZoneManager.zones[i].x2, l.x + l.length + 1); - assert.equal(mouseZoneManager.zones[i].y1, terminal.buffer.lines.length); - assert.equal(mouseZoneManager.zones[i].y2, terminal.buffer.lines.length); + assert.equal(mouseZoneManager.zones[i].y1, bufferService.buffer.lines.length); + assert.equal(mouseZoneManager.zones[i].y2, bufferService.buffer.lines.length); }); done(); }, 0); @@ -111,7 +105,7 @@ describe('Linkifier', () => { describe('after attachToDom', () => { beforeEach(() => { - linkifier.attachToDom(mouseZoneManager); + linkifier.attachToDom(null, mouseZoneManager); }); describe('link matcher', () => { @@ -144,19 +138,23 @@ describe('Linkifier', () => { }); describe('multi-line links', () => { it('should match links that start on line 1/2 of a wrapped line and end on the last character of line 1/2', done => { - (terminal as any).cols = 4; + bufferService.resize(4, bufferService.rows); + bufferService.buffer.lines.length = 0; assertLinkifiesMultiLineLink('12345', /1234/, [{x1: 0, x2: 4, y1: 0, y2: 0}], done); }); it('should match links that start on line 1/2 of a wrapped line and wrap to line 2/2', done => { - (terminal as any).cols = 4; + bufferService.resize(4, bufferService.rows); + bufferService.buffer.lines.length = 0; assertLinkifiesMultiLineLink('12345', /12345/, [{x1: 0, x2: 1, y1: 0, y2: 1}], done); }); it('should match links that start and end on line 2/2 of a wrapped line', done => { - (terminal as any).cols = 4; + bufferService.resize(4, bufferService.rows); + bufferService.buffer.lines.length = 0; assertLinkifiesMultiLineLink('12345678', /5678/, [{x1: 0, x2: 4, y1: 1, y2: 1}], done); }); it('should match links that start on line 2/3 of a wrapped line and wrap to line 3/3', done => { - (terminal as any).cols = 4; + bufferService.resize(4, bufferService.rows); + bufferService.buffer.lines.length = 0; assertLinkifiesMultiLineLink('123456789', /56789/, [{x1: 0, x2: 1, y1: 1, y2: 2}], done); }); }); @@ -164,6 +162,7 @@ describe('Linkifier', () => { describe('validationCallback', () => { it('should enable link if true', done => { + bufferService.buffer.lines.length = 0; addRow('test'); linkifier.registerLinkMatcher(/test/, () => done(), { validationCallback: (url, cb) => { @@ -251,7 +250,7 @@ describe('Linkifier', () => { terminal = new TestTerminal({cols: 10, rows: 5}); linkifier = new TestLinkifier(terminal); mouseZoneManager = new TestMouseZoneManager(); - linkifier.attachToDom(mouseZoneManager); + linkifier.attachToDom(null, mouseZoneManager); }); function assertLinkifiesInTerminal(rowText: string, linkMatcherRegex: RegExp, links: {x1: number, y1: number, x2: number, y2: number}[], done: MochaDone): void { diff --git a/src/Linkifier.ts b/src/Linkifier.ts index 769f3a50..ee585a48 100644 --- a/src/Linkifier.ts +++ b/src/Linkifier.ts @@ -3,12 +3,12 @@ * @license MIT */ -import { ILinkifierEvent, ILinkMatcher, LinkMatcherHandler, ILinkMatcherOptions, ILinkifier, ITerminal, IMouseZoneManager } from './Types'; +import { ILinkifierEvent, ILinkMatcher, LinkMatcherHandler, ILinkMatcherOptions, ILinkifier, IMouseZoneManager } from './Types'; import { IBufferStringIteratorResult } from 'common/buffer/Types'; import { MouseZone } from './MouseZoneManager'; import { getStringCellWidth } from 'common/CharWidth'; import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { ILogService } from 'common/services/Services'; +import { ILogService, IBufferService } from 'common/services/Services'; /** * Limit of the unwrapping line expansion (overscan) at the top and bottom @@ -30,7 +30,9 @@ export class Linkifier implements ILinkifier { protected _linkMatchers: ILinkMatcher[] = []; - private _mouseZoneManager: IMouseZoneManager; + private _mouseZoneManager: IMouseZoneManager | undefined; + private _element: HTMLElement | undefined; + private _rowsTimeoutId: number; private _nextLinkMatcherId = 0; private _rowsToLinkify: { start: number, end: number }; @@ -43,8 +45,8 @@ export class Linkifier implements ILinkifier { public get onLinkTooltip(): IEvent { return this._onLinkTooltip.event; } constructor( - protected _terminal: ITerminal, - private _logService: ILogService + protected readonly _bufferService: IBufferService, + private readonly _logService: ILogService ) { this._rowsToLinkify = { start: null, @@ -56,7 +58,8 @@ export class Linkifier implements ILinkifier { * Attaches the linkifier to the DOM, enabling linkification. * @param mouseZoneManager The mouse zone manager to register link zones with. */ - public attachToDom(mouseZoneManager: IMouseZoneManager): void { + public attachToDom(element: HTMLElement, mouseZoneManager: IMouseZoneManager): void { + this._element = element; this._mouseZoneManager = mouseZoneManager; } @@ -95,7 +98,7 @@ export class Linkifier implements ILinkifier { */ private _linkifyRows(): void { this._rowsTimeoutId = null; - const buffer = this._terminal.buffer; + const buffer = this._bufferService.buffer; // Ensure the start row exists const absoluteRowIndexStart = buffer.ydisp + this._rowsToLinkify.start; @@ -104,7 +107,7 @@ export class Linkifier implements ILinkifier { } // Invalidate bad end row values (if a resize happened) - const absoluteRowIndexEnd = buffer.ydisp + Math.min(this._rowsToLinkify.end, this._terminal.rows) + 1; + const absoluteRowIndexEnd = buffer.ydisp + Math.min(this._rowsToLinkify.end, this._bufferService.rows) + 1; // Iterate over the range of unwrapped content strings within start..end // (excluding). @@ -116,8 +119,8 @@ export class Linkifier implements ILinkifier { // the viewport to +OVERSCAN_CHAR_LIMIT chars (overscan) at top and bottom. // This comes with the tradeoff that matches longer than OVERSCAN_CHAR_LIMIT // chars will not match anymore at the viewport borders. - const overscanLineLimit = Math.ceil(OVERSCAN_CHAR_LIMIT / this._terminal.cols); - const iterator = this._terminal.buffer.iterator( + const overscanLineLimit = Math.ceil(OVERSCAN_CHAR_LIMIT / this._bufferService.cols); + const iterator = this._bufferService.buffer.iterator( false, absoluteRowIndexStart, absoluteRowIndexEnd, overscanLineLimit, overscanLineLimit); while (iterator.hasNext()) { const lineData: IBufferStringIteratorResult = iterator.next(); @@ -228,13 +231,13 @@ export class Linkifier implements ILinkifier { } // get the buffer index as [absolute row, col] for the match - const bufferIndex = this._terminal.buffer.stringIndexToBufferIndex(rowIndex, stringIndex); + const bufferIndex = this._bufferService.buffer.stringIndexToBufferIndex(rowIndex, stringIndex); if (bufferIndex[0] < 0) { // invalid bufferIndex (should not have happened) break; } - const line = this._terminal.buffer.lines.get(bufferIndex[0]); + const line = this._bufferService.buffer.lines.get(bufferIndex[0]); const attr = line.getFg(bufferIndex[1]); let fg: number | undefined; if (attr) { @@ -248,11 +251,11 @@ export class Linkifier implements ILinkifier { return; } if (isValid) { - this._addLink(bufferIndex[1], bufferIndex[0] - this._terminal.buffer.ydisp, uri, matcher, fg); + this._addLink(bufferIndex[1], bufferIndex[0] - this._bufferService.buffer.ydisp, uri, matcher, fg); } }); } else { - this._addLink(bufferIndex[1], bufferIndex[0] - this._terminal.buffer.ydisp, uri, matcher, fg); + this._addLink(bufferIndex[1], bufferIndex[0] - this._bufferService.buffer.ydisp, uri, matcher, fg); } } } @@ -267,12 +270,12 @@ export class Linkifier implements ILinkifier { */ private _addLink(x: number, y: number, uri: string, matcher: ILinkMatcher, fg: number): void { const width = getStringCellWidth(uri); - const x1 = x % this._terminal.cols; - const y1 = y + Math.floor(x / this._terminal.cols); - let x2 = (x1 + width) % this._terminal.cols; - let y2 = y1 + Math.floor((x1 + width) / this._terminal.cols); + const x1 = x % this._bufferService.cols; + const y1 = y + Math.floor(x / this._bufferService.cols); + let x2 = (x1 + width) % this._bufferService.cols; + let y2 = y1 + Math.floor((x1 + width) / this._bufferService.cols); if (x2 === 0) { - x2 = this._terminal.cols; + x2 = this._bufferService.cols; y2--; } @@ -289,7 +292,7 @@ export class Linkifier implements ILinkifier { }, () => { this._onLinkHover.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); - this._terminal.element.classList.add('xterm-cursor-pointer'); + this._element.classList.add('xterm-cursor-pointer'); }, e => { this._onLinkTooltip.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); @@ -299,7 +302,7 @@ export class Linkifier implements ILinkifier { }, () => { this._onLinkLeave.fire(this._createLinkHoverEvent(x1, y1, x2, y2, fg)); - this._terminal.element.classList.remove('xterm-cursor-pointer'); + this._element.classList.remove('xterm-cursor-pointer'); if (matcher.hoverLeaveCallback) { matcher.hoverLeaveCallback(); } @@ -314,6 +317,6 @@ export class Linkifier implements ILinkifier { } private _createLinkHoverEvent(x1: number, y1: number, x2: number, y2: number, fg: number): ILinkifierEvent { - return { x1, y1, x2, y2, cols: this._terminal.cols, fg }; + return { x1, y1, x2, y2, cols: this._bufferService.cols, fg }; } } diff --git a/src/Terminal.ts b/src/Terminal.ts index a97eeeed..c3b392a5 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -304,9 +304,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._inputHandler.onLineFeed(() => this._onLineFeed.fire()); this.register(this._inputHandler); - this._selectionService = this._selectionService || null; - this.linkifier = this.linkifier || new Linkifier(this, this._logService); - this._mouseZoneManager = this._mouseZoneManager || null; + this.linkifier = this.linkifier || new Linkifier(this._bufferService, this._logService); if (this.options.windowsMode) { this._windowsMode = applyWindowsMode(this); @@ -603,7 +601,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp this._mouseZoneManager = new MouseZoneManager(this, this._mouseService); this.register(this._mouseZoneManager); this.register(this.onScroll(() => this._mouseZoneManager.clearAll())); - this.linkifier.attachToDom(this._mouseZoneManager); + this.linkifier.attachToDom(this.element, this._mouseZoneManager); this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this._renderService.dimensions, this._charSizeService); this.viewport.onThemeChange(this._colorManager.colors); diff --git a/src/Types.d.ts b/src/Types.d.ts index 1aa05b6c..1c56ef1b 100644 --- a/src/Types.d.ts +++ b/src/Types.d.ts @@ -290,7 +290,7 @@ export interface ILinkifier { onLinkLeave: IEvent; onLinkTooltip: IEvent; - attachToDom(mouseZoneManager: IMouseZoneManager): void; + attachToDom(element: HTMLElement, mouseZoneManager: IMouseZoneManager): void; linkifyRows(start: number, end: number): void; registerLinkMatcher(regex: RegExp, handler: LinkMatcherHandler, options?: ILinkMatcherOptions): number; deregisterLinkMatcher(matcherId: number): boolean;