add workspace grep engine + search.grep/cancel, editor.open --line

The pure-Dart content-search engine behind find-in-files (D-79): walks
the ignore-pruned workspace, fans files across worker isolates
(Isolate.run) for parallelism, matches each line with a literal
indexOf fast-path or a RegExp, and streams match batches with
cooperative cancellation. No ripgrep dependency; the search.grep IPC
contract is engine-agnostic so an rg accelerator can slot in later.

search.grep returns a searchId and streams search.match / search.done
(or search.error) events, mirroring files.watch; search.cancel stops
an in-flight search. The service reuses the files service's resolved
ignore set so both honour the same ignore_files: layering.

editor.open gains an optional 1-based line argument: it converts the
line to a byte offset and sets the initial selection, enabling
click-to-line from search results.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 20:31:18 +02:00
co-authored by Claude Opus 4.8
parent 0c7a6e86d5
commit 399a4d3a3f
10 changed files with 824 additions and 0 deletions
+9
View File
@@ -37,6 +37,7 @@ import 'package:clide/src/daemon/pane_commands.dart';
import 'package:clide/src/daemon/panel_commands.dart';
import 'package:clide/src/daemon/panel_resizer_kernel.dart';
import 'package:clide/src/daemon/pql_commands.dart';
import 'package:clide/src/daemon/search_commands.dart';
import 'package:clide/src/editor/registry.dart' show EditorRegistry;
import 'package:clide/src/git/client.dart';
import 'package:clide/src/cli/argv_dispatch.dart';
@@ -166,6 +167,14 @@ Future<void> main() async {
registerPaneCommands(dispatcher, paneRegistry);
final filesService = FilesService(root: workRoot, events: eventSink);
registerFilesCommands(dispatcher, filesService);
// Search reuses the files service's resolved ignore set so the
// grep honours the same ignore_files: layering (D-4 / D-79).
final searchService = SearchService(
root: workRoot,
ignore: filesService.ignore,
events: eventSink,
);
registerSearchCommands(dispatcher, searchService);
final editorRegistry = EditorRegistry(events: eventSink, workspaceRoot: workRoot);
registerEditorCommands(dispatcher, editorRegistry);
final gitClient = GitClient(toolchain: tc, workDir: workRoot);