Fix issues with link state

- Scrolling will now clear the link renderer
- Refreshing a single line will now recalculate only that line

Fixes #959
Fixes #960
This commit is contained in:
Daniel Imms
2017-09-09 19:06:30 -07:00
parent 948eedba89
commit 0e3518409e
4 changed files with 52 additions and 14 deletions
+23 -8
View File
@@ -49,11 +49,16 @@ export class Linkifier extends EventEmitter implements ILinkifier {
private _mouseZoneManager: IMouseZoneManager; private _mouseZoneManager: IMouseZoneManager;
private _rowsTimeoutId: number; private _rowsTimeoutId: number;
private _nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID; private _nextLinkMatcherId = HYPERTEXT_LINK_MATCHER_ID;
private _rowsToLinkify: {start: number, end: number};
constructor( constructor(
protected _terminal: IBufferAccessor & IElementAccessor protected _terminal: IBufferAccessor & IElementAccessor
) { ) {
super(); super();
this._rowsToLinkify = {
start: null,
end: null
};
this.registerLinkMatcher(strictUrlRegex, null, { matchIndex: 1 }); this.registerLinkMatcher(strictUrlRegex, null, { matchIndex: 1 });
} }
@@ -76,25 +81,35 @@ export class Linkifier extends EventEmitter implements ILinkifier {
return; return;
} }
// Clear out any existing links // Increase range to linkify
this._mouseZoneManager.clearAll(); if (!this._rowsToLinkify.start) {
this._rowsToLinkify.start = start;
this._rowsToLinkify.end = end;
} else {
this._rowsToLinkify.start = this._rowsToLinkify.start < start ? this._rowsToLinkify.start : start;
this._rowsToLinkify.end = this._rowsToLinkify.end < end ? this._rowsToLinkify.end : end;
}
// Clear out any existing links on this row range
this._mouseZoneManager.clearAll(start, end);
// Restart timer
if (this._rowsTimeoutId) { if (this._rowsTimeoutId) {
clearTimeout(this._rowsTimeoutId); clearTimeout(this._rowsTimeoutId);
} }
this._rowsTimeoutId = setTimeout(this._linkifyRows.bind(this, start, end), Linkifier.TIME_BEFORE_LINKIFY); this._rowsTimeoutId = <number><any>setTimeout(() => this._linkifyRows(), Linkifier.TIME_BEFORE_LINKIFY);
} }
/** /**
* Linkifies * Linkifies the rows requested.
* @param start The row to start at.
* @param end The row to end at.
*/ */
private _linkifyRows(start: number, end: number): void { private _linkifyRows(): void {
this._rowsTimeoutId = null; this._rowsTimeoutId = null;
for (let i = start; i <= end; i++) { for (let i = this._rowsToLinkify.start; i <= this._rowsToLinkify.end; i++) {
this._linkifyRow(i); this._linkifyRow(i);
} }
this._rowsToLinkify.start = null;
this._rowsToLinkify.end = null;
} }
/** /**
+6 -2
View File
@@ -48,8 +48,11 @@ import { MouseZoneManager } from './input/MouseZoneManager';
import { initialize as initializeCharAtlas } from './renderer/CharAtlas'; import { initialize as initializeCharAtlas } from './renderer/CharAtlas';
import { IRenderer } from './renderer/Interfaces'; import { IRenderer } from './renderer/Interfaces';
// Declare for RequireJS in loadAddon // Declares required for loadAddon
declare var exports: any;
declare var module: any;
declare var define: any; declare var define: any;
declare var require: any;
// Let it work inside Node.js for automated testing purposes. // Let it work inside Node.js for automated testing purposes.
const document = (typeof window !== 'undefined') ? window.document : null; const document = (typeof window !== 'undefined') ? window.document : null;
@@ -588,6 +591,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
this.syncBellSound(); this.syncBellSound();
this._mouseZoneManager = new MouseZoneManager(this); this._mouseZoneManager = new MouseZoneManager(this);
this.on('scroll', () => this._mouseZoneManager.clearAll());
this.linkifier.attachToDom(this._mouseZoneManager); this.linkifier.attachToDom(this._mouseZoneManager);
// Create the container that will hold helpers like the textarea for // Create the container that will hold helpers like the textarea for
@@ -1034,7 +1038,7 @@ export class Terminal extends EventEmitter implements ITerminal, IInputHandlingT
*/ */
private queueLinkification(start: number, end: number): void { private queueLinkification(start: number, end: number): void {
if (this.linkifier) { if (this.linkifier) {
this.linkifier.linkifyRows(0, this.rows); this.linkifier.linkifyRows(start, end);
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@
export interface IMouseZoneManager { export interface IMouseZoneManager {
add(zone: IMouseZone): void; add(zone: IMouseZone): void;
clearAll(): void; clearAll(start?: number, end?: number): void;
} }
export interface IMouseZone { export interface IMouseZone {
+22 -3
View File
@@ -44,9 +44,28 @@ export class MouseZoneManager implements IMouseZoneManager {
} }
} }
public clearAll(): void { public clearAll(start?: number, end?: number): void {
this._zones.length = 0; // Exit if there's nothing to clear
this._deactivate(); if (this._zones.length === 0) {
return;
}
// Iterate through zones and clear them out if they're within the range
for (let i = 0; i < this._zones.length; i++) {
const zone = this._zones[i];
if (zone.y >= start && zone.y <= end) {
if (this._currentZone && this._currentZone === zone) {
this._currentZone.leaveCallback();
this._currentZone = null;
}
this._zones.splice(i--, 1);
}
}
// Deactivate the mouse zone manager if all the zones have been removed
if (this._zones.length === 0) {
this._deactivate();
}
} }
private _activate(): void { private _activate(): void {