@@ -35,6 +35,13 @@ fn collect_files_inner(dir_path: &Path, collected: &mut Vec<PathBuf>) -> Result<
3535 if is_ignored_path ( & path) {
3636 continue ;
3737 }
38+ // Ignore files larger than 100 MB to avoid blocking search
39+ const MAX_FILE_SIZE : u64 = 100 * 1024 * 1024 ; // 100 MB
40+ if let Ok ( metadata) = std:: fs:: metadata ( & path) {
41+ if metadata. len ( ) > MAX_FILE_SIZE {
42+ continue ;
43+ }
44+ }
3845 collected. push ( path) ;
3946 }
4047 }
@@ -131,35 +138,25 @@ pub async fn file_search(
131138 file_path : & str ,
132139 pattern : & str ,
133140 cancel_token : CancellationToken ,
134- result_tx : mpsc:: Sender < SearchResult > ,
135- ) -> Result < ( ) > {
141+ ) -> Result < Vec < SearchResult > > {
142+ let mut results = Vec :: new ( ) ;
143+
136144 // Check if pattern is multi-line (contains newline)
137145 let is_multiline = pattern. contains ( '\n' ) ;
138146
139147 if is_multiline {
140148 // For multi-line patterns, read entire file content
141149 if cancel_token. is_cancelled ( ) {
142- return Ok ( ( ) ) ;
150+ return Ok ( results ) ;
143151 }
144152
145153 let content = tokio:: fs:: read_to_string ( file_path) . await ?;
146154
147155 if cancel_token. is_cancelled ( ) {
148- return Ok ( ( ) ) ;
156+ return Ok ( results ) ;
149157 }
150158
151- let results = multiline_search ( & content, pattern) ;
152-
153- for result in results {
154- if cancel_token. is_cancelled ( ) {
155- break ;
156- }
157-
158- if let Err ( e) = result_tx. send ( result) . await {
159- eprintln ! ( "Failed to send result: {}" , e) ;
160- break ;
161- }
162- }
159+ results = multiline_search ( & content, pattern) ;
163160 } else {
164161 // For single-line patterns, use line-by-line processing (more memory efficient)
165162 let path = Path :: new ( file_path) ;
@@ -171,32 +168,31 @@ pub async fn file_search(
171168
172169 loop {
173170 tokio:: select! {
174- line = lines. next_line( ) => {
175- match line ? {
171+ line_result = lines. next_line( ) => {
172+ match line_result ? {
176173 Some ( content) => {
177- if cancel_token. is_cancelled( ) { break }
178-
179- let line_results = line_search( & content, pattern, line_number) ;
180-
181- for result in line_results {
182- if let Err ( e) = result_tx. send( result) . await {
183- eprintln!( "Failed to send result: {}" , e) ;
184- break ;
185- }
174+ if cancel_token. is_cancelled( ) {
175+ break ;
186176 }
187177
178+ let line_results = line_search( & content, pattern, line_number) ;
179+ results. extend( line_results) ;
188180 line_number += 1 ;
189181 }
190182 // End of file reached
191- None => { break }
183+ None => {
184+ break ;
185+ }
192186 }
193187 }
194- _ = cancel_token. cancelled( ) => { break }
188+ _ = cancel_token. cancelled( ) => {
189+ break ;
190+ }
195191 }
196192 }
197193 }
198194
199- Ok ( ( ) )
195+ Ok ( results )
200196}
201197
202198#[ derive( Debug , Serialize , Deserialize , Clone ) ]
@@ -240,37 +236,25 @@ pub async fn global_search(
240236 let handle = tokio:: spawn ( async move {
241237 let _permit = permit;
242238
243- let ( search_result_tx, mut search_result_rx) = mpsc:: channel ( 100 ) ;
244- let cancel = cancel_token. clone ( ) ;
245-
246239 let file_path_str = path_buf. to_string_lossy ( ) . to_string ( ) ;
247240 let display_path = relative_to_current_dir ( & path_buf)
248241 . map ( |p| p. to_string_lossy ( ) . to_string ( ) )
249242 . unwrap_or_else ( || file_path_str. clone ( ) ) ;
250-
251- tokio:: select! {
252- res = file_search( & file_path_str, & pattern, cancel, search_result_tx) => {
253- if let Err ( err) = res {
254- // eprintln!("Error searching in file {}: {}", file_path_str, err);
255- return ;
256- }
257- }
258- _ = cancel_token. cancelled( ) => {
243+
244+ let matches = match file_search ( & file_path_str, & pattern, cancel_token. clone ( ) ) . await {
245+ Ok ( m) => m,
246+ Err ( _err) => {
247+ // Error reading/searching file, skip it
259248 return ;
260249 }
261- }
262-
263- let mut matches = Vec :: new ( ) ;
264- while let Some ( result) = search_result_rx. recv ( ) . await {
265- matches. push ( result) ;
266- }
250+ } ;
267251
268252 if !matches. is_empty ( ) {
269253 if result_tx. send ( FileSearchResult {
270254 file_path : display_path,
271255 matches,
272256 } ) . await . is_err ( ) {
273- eprintln ! ( " Global receiver dropped. Skipping results" ) ;
257+ // Global receiver dropped, skip results
274258 }
275259 }
276260 } ) ;
@@ -375,23 +359,12 @@ pub mod search_exp {
375359 let temp_file_path = temp_file. path ( ) . to_path_buf ( ) ;
376360
377361 let cancel = CancellationToken :: new ( ) ;
378- let ( result_tx, mut result_rx) = mpsc:: channel ( 10 ) ;
379-
380- let handle = tokio:: spawn ( async move {
381- file_search (
382- temp_file_path. to_string_lossy ( ) . as_ref ( ) ,
383- pattern,
384- cancel,
385- result_tx,
386- ) . await . unwrap ( ) ;
387- } ) ;
388-
389- let mut results = Vec :: new ( ) ;
390- while let Some ( result) = result_rx. recv ( ) . await {
391- results. push ( result) ;
392- }
393362
394- handle. await ?;
363+ let results = file_search (
364+ temp_file_path. to_string_lossy ( ) . as_ref ( ) ,
365+ pattern,
366+ cancel,
367+ ) . await ?;
395368
396369 println ! ( "Results: {:?}" , results) ;
397370
@@ -422,41 +395,23 @@ pub mod search_exp {
422395 let temp_file_path = temp_file. path ( ) . to_path_buf ( ) ;
423396
424397 let cancel = CancellationToken :: new ( ) ;
425- let ( result_tx, mut result_rx) = mpsc:: channel ( 10 ) ;
426-
427- let cancel_clone = cancel. clone ( ) ;
428398
429- // Spawn the function in a task
430- let handle = tokio:: spawn ( async move {
431- file_search (
432- temp_file_path. to_string_lossy ( ) . as_ref ( ) ,
433- pattern,
434- cancel_clone,
435- result_tx,
436- ) . await . unwrap ( ) ;
437- } ) ;
438-
439- // Send cancellation signal after a short delay
440- tokio:: spawn ( async move {
441- // sleep(Duration::from_millis(10)).await; // Adjust the delay as needed
442- cancel. cancel ( ) ;
443- } ) ;
399+ // Send cancellation signal immediately
400+ cancel. cancel ( ) ;
444401
445- // Collect results until cancellation
446- let mut results = Vec :: new ( ) ;
447- while let Some ( result) = result_rx. recv ( ) . await {
448- results. push ( result) ;
449- }
402+ // Search should return empty results when cancelled
403+ let results = file_search (
404+ temp_file_path. to_string_lossy ( ) . as_ref ( ) ,
405+ pattern,
406+ cancel,
407+ ) . await ?;
450408
451409 println ! ( "Results len: {}" , results. len( ) ) ;
452410 println ! ( "Results: {:?}" , results) ;
453411
454412 // Assert that processing stopped before completing
455413 // We expect 0 results to be returned.
456414 assert ! ( results. len( ) == 0 ) ;
457-
458- // Ensure the search task completes
459- handle. await ?;
460415
461416 Ok ( ( ) )
462417 }
@@ -557,23 +512,12 @@ pub mod search_exp {
557512 let pattern = "second line\n third line" ;
558513
559514 let cancel = CancellationToken :: new ( ) ;
560- let ( result_tx, mut result_rx) = mpsc:: channel ( 10 ) ;
561-
562- let handle = tokio:: spawn ( async move {
563- file_search (
564- temp_file_path. to_string_lossy ( ) . as_ref ( ) ,
565- pattern,
566- cancel,
567- result_tx,
568- ) . await . unwrap ( ) ;
569- } ) ;
570-
571- let mut results = Vec :: new ( ) ;
572- while let Some ( result) = result_rx. recv ( ) . await {
573- results. push ( result) ;
574- }
575515
576- handle. await ?;
516+ let results = file_search (
517+ temp_file_path. to_string_lossy ( ) . as_ref ( ) ,
518+ pattern,
519+ cancel,
520+ ) . await ?;
577521
578522 assert_eq ! ( results. len( ) , 1 ) ;
579523 assert_eq ! ( results[ 0 ] . line, 1 ) ; // second line is at index 1
0 commit comments