Remove ITerminal from Linkifier

This commit is contained in:
Daniel Imms
2019-07-13 13:47:17 -07:00
parent a696f4747a
commit 1ffa568a2f
4 changed files with 52 additions and 52 deletions
+24 -25
View File
@@ -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();
(<MockBuffer>terminal.buffer).setLines(new CircularList<IBufferLine>(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 {
+25 -22
View File
@@ -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<ILinkifierEvent> { 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 };
}
}
+2 -4
View File
@@ -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);
+1 -1
View File
@@ -290,7 +290,7 @@ export interface ILinkifier {
onLinkLeave: IEvent<ILinkifierEvent>;
onLinkTooltip: IEvent<ILinkifierEvent>;
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;