search method
Finds query in the active buffer.
Soft-wrapped physical rows are searched as one logical line. Search
results are capped by maxResults so repeated output cannot cause
unbounded result allocation.
Implementation
List<TerminalSearchMatch> search(
String query, {
bool caseSensitive = false,
bool wholeWord = false,
bool useRegex = false,
int maxResults = _defaultSearchResultLimit,
}) {
if (query.isEmpty || maxResults <= 0) {
return const [];
}
final pattern = switch (useRegex) {
true => query,
false => RegExp.escape(query),
};
final expression = RegExp(
pattern,
caseSensitive: caseSensitive,
unicode: true,
);
final results = <TerminalSearchMatch>[];
final buffer = this.buffer;
final textBuffer = StringBuffer();
final searchCells = _SearchCells();
var lineIndex = 0;
while (lineIndex < buffer.lines.length && results.length < maxResults) {
final logicalLine = _buildLogicalLine(
buffer,
lineIndex,
textBuffer,
searchCells,
);
lineIndex = logicalLine.nextLineIndex;
if (logicalLine.text.isEmpty || logicalLine.cells.isEmpty) continue;
for (final match in expression.allMatches(logicalLine.text)) {
if (match.start == match.end) continue;
if (wholeWord && !_isWholeWord(logicalLine.text, match)) continue;
final startCell = logicalLine.cells.cellAt(buffer, match.start);
final endCell = logicalLine.cells.cellAt(buffer, match.end - 1);
if (startCell == null || endCell == null) continue;
results.add(
TerminalSearchMatch(
range: BufferRangeLine(
CellOffset(startCell.x, startCell.y),
CellOffset(endCell.x + endCell.width, endCell.y),
),
text: logicalLine.text.substring(match.start, match.end),
),
);
if (results.length >= maxResults) break;
}
}
return results;
}