diff --git a/addons/addon-search/src/SearchAddon.ts b/addons/addon-search/src/SearchAddon.ts index 3aaae4ee1..ff5440088 100644 --- a/addons/addon-search/src/SearchAddon.ts +++ b/addons/addon-search/src/SearchAddon.ts @@ -133,23 +133,7 @@ export class SearchAddon extends Disposable implements ITerminalAddon, ISearchAp // new search, clear out the old decorations this.clearDecorations(true); - const results: ISearchResult[] = []; - let prevResult: ISearchResult | undefined = undefined; - let result = this._engine.find(term, 0, 0, searchOptions); - - while (result && (prevResult?.row !== result.row || prevResult?.col !== result.col)) { - if (results.length >= this._highlightLimit) { - break; - } - prevResult = result; - results.push(prevResult); - result = this._engine.find( - term, - prevResult.col + prevResult.term.length >= this._terminal.cols ? prevResult.row + 1 : prevResult.row, - prevResult.col + prevResult.term.length >= this._terminal.cols ? 0 : prevResult.col + 1, - searchOptions - ); - } + const results = this._engine.collectMatches(term, searchOptions, this._highlightLimit); this._resultTracker.updateResults(results, this._highlightLimit); if (searchOptions.decorations) { diff --git a/addons/addon-search/src/SearchEngine.ts b/addons/addon-search/src/SearchEngine.ts index 12c29b618..b970c0a25 100644 --- a/addons/addon-search/src/SearchEngine.ts +++ b/addons/addon-search/src/SearchEngine.ts @@ -72,19 +72,63 @@ export class SearchEngine { } this._lineCache.initLinesCache(); + const lineSearchRegex = this._createLineSearchRegex(term, searchOptions); + return this._findFromPosition(term, startRow, startCol, searchOptions, lineSearchRegex); + } + /** + * Collect up to `maxResults` matches from the start of the buffer in a single search session. + */ + public collectMatches(term: string, searchOptions?: ISearchOptions, maxResults: number = Number.MAX_SAFE_INTEGER): ISearchResult[] { + if (!term || term.length === 0) { + return []; + } + + this._lineCache.initLinesCache(); + const lineSearchRegex = this._createLineSearchRegex(term, searchOptions); + const results: ISearchResult[] = []; + let startRow = 0; + let startCol = 0; + const cols = this._terminal.cols; + + while (results.length < maxResults) { + const result = this._findFromPosition(term, startRow, startCol, searchOptions, lineSearchRegex); + if (!result) { + break; + } + const prevResult = results[results.length - 1]; + if (prevResult && prevResult.row === result.row && prevResult.col === result.col) { + break; + } + results.push(result); + if (result.col + result.term.length >= cols) { + startRow = result.row + 1; + startCol = 0; + } else { + startRow = result.row; + startCol = result.col + 1; + } + } + + return results; + } + + private _findFromPosition( + term: string, + startRow: number, + startCol: number, + searchOptions: ISearchOptions | undefined, + lineSearchRegex: RegExp | undefined + ): ISearchResult | undefined { const searchPosition: ISearchPosition = { startRow, startCol }; - const lineSearchRegex = this._createLineSearchRegex(term, searchOptions); - - // Search startRow let result = this._findInLine(term, searchPosition, searchOptions, false, lineSearchRegex); - // Search from startRow + 1 to end if (!result) { - for (let y = startRow + 1; y < this._terminal.buffer.active.baseY + this._terminal.rows; y++) { + const bufferEnd = this._terminal.buffer.active.baseY + this._terminal.rows; + for (let y = startRow + 1; y < bufferEnd; y++) { searchPosition.startRow = y; searchPosition.startCol = 0; result = this._findInLine(term, searchPosition, searchOptions, false, lineSearchRegex);