add find-in-files sidebar panel + Ctrl/Cmd+Shift+F

The find-in-files UI on top of the search.grep engine. A
FindInFilesController drives search.grep, accumulates streamed
search.match events (scoped to the active searchId, stale ids
ignored) grouped by file, and opens a match in the editor at its line.
The SearchPanelView contributes a sidebar tab: a debounced query box,
regex + case toggles, include/exclude glob fields, and a grouped
results list with the matched span highlighted.

findInFiles.open (Ctrl/Cmd+Shift+F) reveals and activates the search
tab.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 20:53:50 +02:00
co-authored by Claude Opus 4.8
parent 399a4d3a3f
commit f96c565acd
13 changed files with 695 additions and 7 deletions
+7 -7
View File
@@ -18,10 +18,12 @@ void main() {
setUp(() async {
f = await KernelFixture.create();
f.ipc.stub('files.walk', (_) async => IpcResponse.ok(id: '1', data: const {
'files': ['lib/main.dart', 'lib/app.dart', 'README.md'],
'truncated': false,
}));
f.ipc.stub(
'files.walk',
(_) async => IpcResponse.ok(id: '1', data: const {
'files': ['lib/main.dart', 'lib/app.dart', 'README.md'],
'truncated': false,
}));
f.ipc.stub('editor.open', (args) async => IpcResponse.ok(id: '1', data: {'path': args['path']}));
});
tearDown(() => f.dispose());
@@ -63,9 +65,7 @@ void main() {
testWidgets('tapping an md result publishes to the markdown reader bus', (tester) async {
final published = <Message>[];
final sub = f.services.messages
.subscribe(publisher: 'builtin.markdown', channel: 'selection')
.listen(published.add);
final sub = f.services.messages.subscribe(publisher: 'builtin.markdown', channel: 'selection').listen(published.add);
addTearDown(sub.cancel);
await tester.pumpWidget(harness(f, const QuickOpenOverlay()));