ripGrepStream function
Stream lines from ripgrep as they arrive, calling onLines per stdout
chunk.
Unlike ripGrep which buffers the entire stdout, this flushes complete lines as soon as each chunk arrives. Partial trailing lines are carried across chunk boundaries.
Callers that want to stop early should cancel via the returned subscription or use a timeout. No EAGAIN retry, no internal timeout, stderr is ignored; interactive callers own recovery.
Implementation
Future<void> ripGrepStream(
List<String> args,
String target, {
required void Function(List<String> lines) onLines,
}) async {
await _codesignRipgrepIfNecessary();
final (:rgPath, :rgArgs, :argv0) = ripgrepCommand();
final process = await Process.start(rgPath, [
...rgArgs,
...args,
target,
], environment: argv0 != null ? {'ARGV0': argv0} : null);
String remainder = '';
await process.stdout.transform(const SystemEncoding().decoder).forEach((
chunk,
) {
final data = remainder + chunk;
final lines = data.split('\n');
remainder = lines.removeLast();
if (lines.isNotEmpty) {
onLines(lines.map(_stripCR).toList());
}
});
// Flush remaining.
if (remainder.isNotEmpty) {
onLines([_stripCR(remainder)]);
}
final exitCode = await process.exitCode;
if (exitCode != 0 && exitCode != 1) {
throw Exception('ripgrep exited with code $exitCode');
}
}