Support multiline links in the WebLinksAddon

This commit is contained in:
Jon Bockhorst
2019-11-05 23:35:20 -06:00
parent b3d95d20dc
commit ac6c8a5bd3
3 changed files with 70 additions and 14 deletions
@@ -1,3 +1,8 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { ILinkProvider, IBufferCellPosition, ILink, Terminal, IBuffer } from 'xterm';
export class WebLinkProvider implements ILinkProvider {
@@ -11,20 +16,15 @@ export class WebLinkProvider implements ILinkProvider {
}
provideLink(position: IBufferCellPosition, callback: (link: ILink | undefined) => void): void {
callback(LinkComputer.computeLink(position, this._regex, this._terminal.buffer, this._handler));
callback(LinkComputer.computeLink(position, this._regex, this._terminal, this._handler));
}
}
export class LinkComputer {
public static computeLink(position: IBufferCellPosition, regex: RegExp, buffer: IBuffer, handle: (event: MouseEvent, uri: string) => void): ILink | undefined {
public static computeLink(position: IBufferCellPosition, regex: RegExp, terminal: Terminal, handle: (event: MouseEvent, uri: string) => void): ILink | undefined {
const rex = new RegExp(regex.source, (regex.flags || '') + 'g');
const bufferLine = buffer.getLine(position.y - 1);
if (!bufferLine) {
return;
}
const line = bufferLine.translateToString();
const [line, startLineIndex] = LinkComputer._translateBufferLineToStringWithWrap(position.y - 1, false, terminal);
let match;
let stringIndex = -1;
@@ -49,18 +49,66 @@ export class LinkComputer {
break;
}
let endX = stringIndex + url.length + 1;
let endY = startLineIndex + 1;
while (endX > terminal.cols) {
endX -= terminal.cols;
endY++;
}
const range = {
start: {
x: stringIndex + 1,
y: position.y
y: startLineIndex + 1
},
end: {
x: stringIndex + url.length + 1,
y: position.y
x: endX,
y: endY
}
};
return { range, url, handle };
}
}
/**
* Gets the entire line for the buffer line
* @param line The line being translated.
* @param trimRight Whether to trim whitespace to the right.
* @param terminal The terminal
*/
private static _translateBufferLineToStringWithWrap(lineIndex: number, trimRight: boolean, terminal: Terminal): [string, number] {
let lineString = '';
let lineWrapsToNext: boolean;
let prevLinesToWrap: boolean;
do {
const line = terminal.buffer.getLine(lineIndex);
if (!line) {
break;
}
if (line.isWrapped) {
lineIndex--;
}
prevLinesToWrap = line.isWrapped;
} while (prevLinesToWrap);
const startLineIndex = lineIndex;
do {
const nextLine = terminal.buffer.getLine(lineIndex + 1);
lineWrapsToNext = nextLine ? nextLine.isWrapped : false;
const line = terminal.buffer.getLine(lineIndex);
if (!line) {
break;
}
lineString += line.translateToString(!lineWrapsToNext && trimRight).substring(0, terminal.cols);
lineIndex++;
} while (lineWrapsToNext);
return [lineString, startLineIndex];
}
}
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
+10 -2
View File
@@ -8,6 +8,7 @@ import { IDisposable } from 'common/Types';
import { IMouseService } from './services/Services';
import { IBufferService, ICoreService } from 'common/services/Services';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { LinkRenderLayer } from './renderer/LinkRenderLayer';
export class Linkifier2 implements ILinkifier2 {
private _element: HTMLElement | undefined;
@@ -206,9 +207,16 @@ export class Linkifier2 implements ILinkifier2 {
* @param position
*/
private _linkAtPosition(link: ILink, position: IBufferCellPosition): boolean {
return link.range.start.x <= position.x &&
const sameLine = link.range.start.y === link.range.end.y;
const wrappedFromLeft = link.range.start.y < position.y;
const wrappedToRight = link.range.end.y > position.y;
// If the start and end have the same y, then the position must be between start and end x
// If not, then handle each case seperately, depending on which way it wraps
return ((sameLine && link.range.start.x <= position.x && link.range.end.x >= position.x) ||
(wrappedFromLeft && link.range.end.x >= position.x) ||
(wrappedToRight && link.range.start.x <= position.x)) &&
link.range.start.y <= position.y &&
link.range.end.x >= position.x &&
link.range.end.y >= position.y;
}