@@ -987,6 +987,9 @@ async fn try_indexed_search(
987987 {
988988 return None ;
989989 }
990+ if opts. max_count == Some ( 0 ) {
991+ return Some ( Vec :: new ( ) ) ;
992+ }
990993
991994 let sc = fs. as_search_capable ( ) ?;
992995 let mut seen_paths = std:: collections:: HashSet :: new ( ) ;
@@ -1038,7 +1041,7 @@ async fn try_indexed_search(
10381041 } else {
10391042 None
10401043 } ,
1041- max_results : None ,
1044+ max_results : opts . max_count ,
10421045 } ;
10431046
10441047 let results = provider. search ( & query) . ok ( ) ?;
@@ -1085,7 +1088,7 @@ mod tests {
10851088 } ;
10861089 use std:: collections:: HashMap ;
10871090 use std:: path:: { Path , PathBuf } ;
1088- use std:: sync:: Arc ;
1091+ use std:: sync:: { Arc , Mutex } ;
10891092
10901093 async fn run_grep ( args : & [ & str ] , stdin : Option < & str > ) -> Result < ExecResult > {
10911094 let grep = Grep ;
@@ -1116,6 +1119,7 @@ mod tests {
11161119 struct IndexedTestFs {
11171120 inner : InMemoryFs ,
11181121 matches : Vec < SearchMatch > ,
1122+ query_max_results : Option < Arc < Mutex < Vec < Option < usize > > > > > ,
11191123 }
11201124
11211125 #[ async_trait:: async_trait]
@@ -1169,12 +1173,24 @@ mod tests {
11691173
11701174 struct IndexedProvider {
11711175 matches : Vec < SearchMatch > ,
1176+ query_max_results : Option < Arc < Mutex < Vec < Option < usize > > > > > ,
11721177 }
11731178
11741179 impl SearchProvider for IndexedProvider {
1175- fn search ( & self , _query : & SearchQuery ) -> Result < SearchResults > {
1180+ fn search ( & self , query : & SearchQuery ) -> Result < SearchResults > {
1181+ if let Some ( query_max_results) = & self . query_max_results {
1182+ query_max_results
1183+ . lock ( )
1184+ . expect ( "query max results lock should not be poisoned" )
1185+ . push ( query. max_results ) ;
1186+ }
1187+ let matches = if let Some ( max_results) = query. max_results {
1188+ self . matches . iter ( ) . take ( max_results) . cloned ( ) . collect ( )
1189+ } else {
1190+ self . matches . clone ( )
1191+ } ;
11761192 Ok ( SearchResults {
1177- matches : self . matches . clone ( ) ,
1193+ matches,
11781194 truncated : false ,
11791195 } )
11801196 }
@@ -1193,6 +1209,7 @@ mod tests {
11931209 fn search_provider ( & self , _path : & Path ) -> Option < Box < dyn SearchProvider > > {
11941210 Some ( Box :: new ( IndexedProvider {
11951211 matches : self . matches . clone ( ) ,
1212+ query_max_results : self . query_max_results . clone ( ) ,
11961213 } ) )
11971214 }
11981215 }
@@ -1203,7 +1220,11 @@ mod tests {
12031220 args : & [ & str ] ,
12041221 ) -> Result < ExecResult > {
12051222 let grep = Grep ;
1206- let fs: Arc < dyn FileSystem > = Arc :: new ( IndexedTestFs { inner, matches } ) ;
1223+ let fs: Arc < dyn FileSystem > = Arc :: new ( IndexedTestFs {
1224+ inner,
1225+ matches,
1226+ query_max_results : None ,
1227+ } ) ;
12071228 let mut vars = HashMap :: new ( ) ;
12081229 let mut cwd = PathBuf :: from ( "/" ) ;
12091230 let args: Vec < String > = args. iter ( ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
@@ -1571,6 +1592,7 @@ mod tests {
15711592 line_number: 1 ,
15721593 line_content: "secret" . to_string( ) ,
15731594 } ] ,
1595+ query_max_results : None ,
15741596 } ) ;
15751597
15761598 let mut vars = HashMap :: new ( ) ;
@@ -1619,6 +1641,7 @@ mod tests {
16191641 let fs: Arc < dyn FileSystem > = Arc :: new ( IndexedTestFs {
16201642 inner,
16211643 matches : Vec :: new ( ) ,
1644+ query_max_results : None ,
16221645 } ) ;
16231646
16241647 let mut vars = HashMap :: new ( ) ;
@@ -1678,6 +1701,7 @@ mod tests {
16781701 line_content: "hidden SECRET" . to_string( ) ,
16791702 } ,
16801703 ] ,
1704+ query_max_results : None ,
16811705 } ) ;
16821706
16831707 let mut vars = HashMap :: new ( ) ;
@@ -1754,6 +1778,72 @@ mod tests {
17541778 assert ! ( result. stdout. contains( "/b/second.txt:needle in b" ) ) ;
17551779 }
17561780
1781+ #[ tokio:: test]
1782+ async fn test_grep_recursive_indexed_search_passes_max_count_to_provider ( ) {
1783+ let inner = InMemoryFs :: new ( ) ;
1784+ inner. mkdir ( Path :: new ( "/dir" ) , true ) . await . unwrap ( ) ;
1785+ inner
1786+ . write_file ( Path :: new ( "/dir/first.txt" ) , b"needle first\n " )
1787+ . await
1788+ . unwrap ( ) ;
1789+ inner
1790+ . write_file ( Path :: new ( "/dir/second.txt" ) , b"needle second\n " )
1791+ . await
1792+ . unwrap ( ) ;
1793+ let query_max_results = Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) ;
1794+ let fs: Arc < dyn FileSystem > = Arc :: new ( IndexedTestFs {
1795+ inner,
1796+ matches : vec ! [
1797+ SearchMatch {
1798+ path: PathBuf :: from( "/dir/first.txt" ) ,
1799+ line_number: 1 ,
1800+ line_content: "needle first" . to_string( ) ,
1801+ } ,
1802+ SearchMatch {
1803+ path: PathBuf :: from( "/dir/second.txt" ) ,
1804+ line_number: 1 ,
1805+ line_content: "needle second" . to_string( ) ,
1806+ } ,
1807+ ] ,
1808+ query_max_results : Some ( query_max_results. clone ( ) ) ,
1809+ } ) ;
1810+
1811+ let grep = Grep ;
1812+ let mut vars = HashMap :: new ( ) ;
1813+ let mut cwd = PathBuf :: from ( "/" ) ;
1814+ let args: Vec < String > = [ "-r" , "-m1" , "needle" , "/dir" ]
1815+ . iter ( )
1816+ . map ( |s| s. to_string ( ) )
1817+ . collect ( ) ;
1818+ let ctx = Context {
1819+ args : & args,
1820+ env : & HashMap :: new ( ) ,
1821+ variables : & mut vars,
1822+ cwd : & mut cwd,
1823+ fs,
1824+ stdin : None ,
1825+ #[ cfg( feature = "http_client" ) ]
1826+ http_client : None ,
1827+ #[ cfg( feature = "git" ) ]
1828+ git_client : None ,
1829+ #[ cfg( feature = "ssh" ) ]
1830+ ssh_client : None ,
1831+ shell : None ,
1832+ } ;
1833+
1834+ let result = grep. execute ( ctx) . await . unwrap ( ) ;
1835+
1836+ assert_eq ! ( result. exit_code, 0 ) ;
1837+ assert_eq ! ( result. stdout, "/dir/first.txt:needle first\n " ) ;
1838+ assert_eq ! (
1839+ query_max_results
1840+ . lock( )
1841+ . expect( "query max results lock should not be poisoned" )
1842+ . as_slice( ) ,
1843+ & [ Some ( 1 ) ]
1844+ ) ;
1845+ }
1846+
17571847 #[ tokio:: test]
17581848 async fn test_grep_recursive_indexed_search_respects_exclude_dir ( ) {
17591849 let inner = InMemoryFs :: new ( ) ;
0 commit comments