From 17a687a2c4a839e669eef04ccba4e10c2932b569 Mon Sep 17 00:00:00 2001 From: maan2003 Date: Sat, 19 Jul 2025 21:20:36 +0530 Subject: [PATCH] grep tool: Warn when no file matches match include pattern --- crates/assistant_tools/src/grep_tool.rs | 17 +++++++++++++++-- crates/collab/src/tests/integration_tests.rs | 11 ++++++++--- crates/project/src/project.rs | 13 ++++++++++--- crates/project/src/project_tests.rs | 2 +- crates/project/src/search.rs | 5 ++++- .../remote_server/src/remote_editing_tests.rs | 7 +++++++ crates/search/src/project_search.rs | 7 +++++-- 7 files changed, 50 insertions(+), 12 deletions(-) diff --git a/crates/assistant_tools/src/grep_tool.rs b/crates/assistant_tools/src/grep_tool.rs index 43c3d1d990..f110f8a313 100644 --- a/crates/assistant_tools/src/grep_tool.rs +++ b/crates/assistant_tools/src/grep_tool.rs @@ -173,7 +173,17 @@ impl Tool for GrepTool { let mut matches_found = 0; let mut has_more_matches = false; - 'outer: while let Some(SearchResult::Buffer { buffer, ranges }) = results.next().await { + let mut any_file_matched_pattern = false; + 'outer: while let Some(result) = results.next().await { + let (buffer, ranges) = match result { + SearchResult::Buffer { buffer, ranges } => { + (buffer,ranges) + } + SearchResult::Finished { any_file_matched_pattern: matched, .. } => { + any_file_matched_pattern = matched; + break 'outer; + } + }; if ranges.is_empty() { continue; } @@ -294,7 +304,10 @@ impl Tool for GrepTool { } } - if matches_found == 0 { + if !any_file_matched_pattern && input.include_pattern.is_some() { + assert_eq!(matches_found, 0, "no matches must be found if any file didn't match"); + Ok("No files found matching the include pattern".to_string().into()) + } else if matches_found == 0 { Ok("No matches found".to_string().into()) } else if has_more_matches { Ok(format!( diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 5a2c40b890..8c2e9197a4 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -5185,10 +5185,15 @@ async fn test_project_search( SearchResult::Buffer { buffer, ranges } => { results.entry(buffer).or_insert(ranges); } - SearchResult::LimitReached => { - panic!( + SearchResult::Finished { + limit_reached, + any_file_matched_pattern, + } => { + assert!( + !limit_reached, "Unexpectedly reached search limit in tests. If you do want to assert limit-reached, change this panic call." - ) + ); + assert!(any_file_matched_pattern); } }; } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b3a9e6fdf5..cb060d4746 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -3841,6 +3841,7 @@ impl Project { let mut range_count = 0; let mut buffer_count = 0; let mut limit_reached = false; + let mut any_file_matched_pattern = false; let query = Arc::new(query); let chunks = matching_buffers_rx.ready_chunks(64); @@ -3850,6 +3851,9 @@ impl Project { // ranges in the buffer matched by the query. let mut chunks = pin!(chunks); 'outer: while let Some(matching_buffer_chunk) = chunks.next().await { + if !matching_buffer_chunk.is_empty() { + any_file_matched_pattern = true; + } let mut chunk_results = Vec::with_capacity(matching_buffer_chunk.len()); for buffer in matching_buffer_chunk { let query = query.clone(); @@ -3886,9 +3890,12 @@ impl Project { } } - if limit_reached { - result_tx.send(SearchResult::LimitReached).await?; - } + result_tx + .send(SearchResult::Finished { + limit_reached, + any_file_matched_pattern, + }) + .await?; anyhow::Ok(()) }) diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index cb3c9efe60..98e7232e8a 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -8892,7 +8892,7 @@ async fn search( SearchResult::Buffer { buffer, ranges } => { results.entry(buffer).or_insert(ranges); } - SearchResult::LimitReached => {} + SearchResult::Finished { .. } => {} } } Ok(results diff --git a/crates/project/src/search.rs b/crates/project/src/search.rs index 4f024837c8..6b046db81f 100644 --- a/crates/project/src/search.rs +++ b/crates/project/src/search.rs @@ -21,7 +21,10 @@ pub enum SearchResult { buffer: Entity, ranges: Vec>, }, - LimitReached, + Finished { + limit_reached: bool, + any_file_matched_pattern: bool, + }, } #[derive(Clone, Copy, PartialEq)] diff --git a/crates/remote_server/src/remote_editing_tests.rs b/crates/remote_server/src/remote_editing_tests.rs index 9730984f26..9150cfbe1a 100644 --- a/crates/remote_server/src/remote_editing_tests.rs +++ b/crates/remote_server/src/remote_editing_tests.rs @@ -222,6 +222,13 @@ async fn test_remote_project_search(cx: &mut TestAppContext, server_cx: &mut Tes ) }); + let SearchResult::Finished { + limit_reached: false, + any_file_matched_pattern: true, + } = receiver.recv().await.unwrap() + else { + panic!("invalid finisher"); + }; assert!(receiver.recv().await.is_err()); buffer } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 15c1099aec..8a9d8cbfe3 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -329,8 +329,11 @@ impl ProjectSearch { project::search::SearchResult::Buffer { buffer, ranges } => { buffers_with_ranges.push((buffer, ranges)); } - project::search::SearchResult::LimitReached => { - limit_reached = true; + project::search::SearchResult::Finished { + limit_reached: reached, + .. + } => { + limit_reached = reached; } } }