mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Remove ITerminal from Linkifier
This commit is contained in:
+24
-25
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Vendored
+1
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user