From d0dc387921604b899700478bacec6614ebcdb96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Breitbart?= Date: Fri, 14 Sep 2018 23:16:24 +0200 Subject: [PATCH] fix overscan issue and enable linkify of partial shown matches --- src/Buffer.ts | 26 +++++++++++++++++++++++--- src/Linkifier.ts | 31 ++++++++++++++++++------------- src/Types.ts | 2 +- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/Buffer.ts b/src/Buffer.ts index 29b034ac..d7760b11 100644 --- a/src/Buffer.ts +++ b/src/Buffer.ts @@ -371,8 +371,8 @@ export class Buffer implements IBuffer { this.markers.splice(this.markers.indexOf(marker), 1); } - public iterator(trimRight: boolean, startIndex?: number, endIndex?: number): IBufferStringIterator { - return new BufferStringIterator(this, trimRight, startIndex, endIndex); + public iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator { + return new BufferStringIterator(this, trimRight, startIndex, endIndex, startOverscan, endOverscan); } } @@ -401,6 +401,18 @@ export class Marker extends EventEmitter implements IMarker { } } +/** + * Iterator to get unwrapped content strings from the buffer. + * The iterator returns at least the string data between the borders + * `startIndex` and `endIndex` (exclusive) and will expand the lines + * by `startOverscan` to the top and by `endOverscan` to the bottom, + * if no new line was found in between. + * It will never read/return string data beyond `startIndex - startOverscan` + * or `endIndex + endOverscan`. Therefore the first and last line might be truncated. + * It is possible to always get the full string for the first and last line as well + * by setting the overscan values to the actual buffer length, but not recommended + * since it might return the whole buffer within a single string in a worst case scenario. + */ export class BufferStringIterator implements IBufferStringIterator { private _current: number; @@ -408,7 +420,9 @@ export class BufferStringIterator implements IBufferStringIterator { private _buffer: IBuffer, private _trimRight: boolean, private _startIndex: number = 0, - private _endIndex: number = _buffer.lines.length + private _endIndex: number = _buffer.lines.length, + private _startOverscan: number = 0, + private _endOverscan: number = 0 ) { this._current = this._startIndex; } @@ -419,6 +433,12 @@ export class BufferStringIterator implements IBufferStringIterator { public next(): IBufferStringIteratorResult { const range = this._buffer.getWrappedRangeForLine(this._current); + if (range.first < this._startIndex - this._startOverscan) { + range.first = this._startIndex - this._startOverscan; + } + if (range.last > this._endIndex + this._endOverscan) { + range.last = this._endIndex + this._endOverscan; + } let result = ''; for (let i = range.first; i <= range.last; ++i) { // TODO: always apply trimRight after fixing #1685 diff --git a/src/Linkifier.ts b/src/Linkifier.ts index 4d84b1a7..b4023bbf 100644 --- a/src/Linkifier.ts +++ b/src/Linkifier.ts @@ -21,6 +21,12 @@ export class Linkifier extends EventEmitter implements ILinkifier { */ protected static readonly TIME_BEFORE_LINKIFY = 200; + /** + * Limit of the unwrapping line expansion (overscan) at the top and bottom + * of the actual viewport. + */ + protected static readonly OVERSCAN_LIMIT = 5; + protected _linkMatchers: ILinkMatcher[] = []; private _mouseZoneManager: IMouseZoneManager; @@ -88,11 +94,17 @@ export class Linkifier extends EventEmitter implements ILinkifier { return; } - // iterate over the range of unwrapped content strings within start..end (excluding) - // _doLinkifyRow gets full unwrapped lines with the start row as buffer offset for every matcher - // for wrapped content over several rows the iterator might return rows outside the viewport - // we skip those later in _doLinkifyRow - const iterator = this._terminal.buffer.iterator(false, absoluteRowIndexStart, this._terminal.buffer.ydisp + this._rowsToLinkify.end + 1); + // Iterate over the range of unwrapped content strings within start..end (excluding). + // _doLinkifyRow gets full unwrapped lines with the start row as buffer offset for every matcher. + // The unwrapping is needed to also match content that got wrapped at the right side. + // To avoid a worst case szenario where the whole buffer contains just a single unwrapped string + // we limit this line expansion beyond the actual viewport to -5 and +5 real buffer lines (overscan). + // This comes with the tradeoff that match longer than 5 buffer lines will not match anymore at the + // viewport borders. + const iterator = this._terminal.buffer.iterator( + false, absoluteRowIndexStart, this._terminal.buffer.ydisp + this._rowsToLinkify.end + 1, + Linkifier.OVERSCAN_LIMIT, Linkifier.OVERSCAN_LIMIT); + console.log('linkify rows', absoluteRowIndexStart, this._terminal.buffer.ydisp + this._rowsToLinkify.end + 1); while (iterator.hasNext()) { const lineData: IBufferStringIteratorResult = iterator.next(); for (let i = 0; i < this._linkMatchers.length; i++) { @@ -204,14 +216,6 @@ export class Linkifier extends EventEmitter implements ILinkifier { // get the buffer index as [absolute row, col] for the match const bufferIndex = this._terminal.buffer.stringIndexToBufferIndex(rowIndex, stringIndex); - // skip rows outside of the viewport - if (bufferIndex[0] - this._terminal.buffer.ydisp < 0) { - continue; - } - if (bufferIndex[0] - this._terminal.buffer.ydisp > this._terminal.rows) { - break; - } - const line = this._terminal.buffer.lines.get(bufferIndex[0]); const char = line.get(bufferIndex[1]); let fg: number | undefined; @@ -254,6 +258,7 @@ export class Linkifier extends EventEmitter implements ILinkifier { x2 = this._terminal.cols; y2--; } + console.log(x1, y1, x2, y2); this._mouseZoneManager.add(new MouseZone( x1 + 1, diff --git a/src/Types.ts b/src/Types.ts index 69c40151..40b3bd02 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -296,7 +296,7 @@ export interface IBuffer { nextStop(x?: number): number; prevStop(x?: number): number; stringIndexToBufferIndex(lineIndex: number, stringIndex: number): number[]; - iterator(trimRight: boolean, startIndex?: number, endIndex?: number): IBufferStringIterator; + iterator(trimRight: boolean, startIndex?: number, endIndex?: number, startOverscan?: number, endOverscan?: number): IBufferStringIterator; } export interface IBufferSet extends IEventEmitter {