search method

Future<SearchResult> search(
  1. String pattern,
  2. SearchScope scope,
  3. SearchOptions options, {
  4. String? targetPath,
})

Search for pattern within the given scope.

Implementation

Future<SearchResult> search(
  String pattern,
  SearchScope scope,
  SearchOptions options, {
  String? targetPath,
}) async {
  final sw = Stopwatch()..start();

  // Build the regex for matching.
  final regex = _buildRegex(pattern, options);

  // Determine which files to search.
  final files = await _resolveScope(scope, targetPath, options);
  final matches = <SearchMatch>[];
  var totalMatches = 0;
  final maxResults = options.maxResults;

  for (final filePath in files) {
    if (maxResults != null && totalMatches >= maxResults) break;

    final file = File(filePath);
    if (!await file.exists()) continue;

    String content;
    try {
      content = await file.readAsString();
    } catch (_) {
      continue; // skip binary / unreadable files
    }

    final lines = content.split('\n');

    for (var i = 0; i < lines.length; i++) {
      final lineMatches = regex.allMatches(lines[i]);
      for (final m in lineMatches) {
        totalMatches++;
        if (maxResults != null && totalMatches > maxResults) break;

        final beforeCtx = <String>[];
        final afterCtx = <String>[];
        for (var b = math.max(0, i - options.contextLines); b < i; b++) {
          beforeCtx.add(lines[b]);
        }
        for (
          var a = i + 1;
          a <= math.min(lines.length - 1, i + options.contextLines);
          a++
        ) {
          afterCtx.add(lines[a]);
        }

        matches.add(
          SearchMatch(
            filePath: filePath,
            lineNumber: i + 1,
            column: m.start,
            matchLength: m.end - m.start,
            lineContent: lines[i],
            beforeContext: beforeCtx,
            afterContext: afterCtx,
          ),
        );
      }
    }
  }

  sw.stop();
  final truncated = maxResults != null && totalMatches > maxResults;

  _addToHistory(pattern, scope, options);

  return SearchResult(
    matches: matches,
    totalMatches: totalMatches,
    filesSearched: files.length,
    duration: sw.elapsed,
    truncated: truncated,
  );
}