@@ -4,14 +4,22 @@ use serde::{Deserialize, Serialize};
44use serde_json:: { self , json} ;
55use socketioxide:: extract:: { Data , SocketRef , State } ;
66use tokio:: sync:: mpsc;
7+ use tokio:: time:: { self , Duration , MissedTickBehavior } ;
78use tokio_util:: sync:: CancellationToken ;
89use tracing:: info;
910
11+ const SEARCH_RESULT_BATCH_INTERVAL : Duration = Duration :: from_millis ( 200 ) ;
12+
1013#[ derive( Debug , Serialize , Deserialize , Clone ) ]
1114pub struct SearchRequest {
1215 pub pattern : String ,
1316}
1417
18+ #[ derive( Debug , Serialize ) ]
19+ struct SearchResultsBatch {
20+ results : Vec < FileSearchResult > ,
21+ }
22+
1523pub async fn handle_search (
1624 socket : SocketRef ,
1725 Data ( search_request) : Data < SearchRequest > ,
@@ -37,6 +45,7 @@ pub async fn handle_search(
3745 // Save the cancel in the socket data
3846 data. search_cancel = Some ( cancel. clone ( ) ) ;
3947 data. search_pattern = Some ( search_request. pattern . clone ( ) ) ;
48+ data. search_last_file_result = None ;
4049
4150 // Prepare search, get the current directory and create channel to collect results
4251 let current_dir = std:: env:: current_dir ( ) . unwrap ( ) ;
@@ -63,10 +72,35 @@ pub async fn handle_search(
6372 // Collect results and send them to the socket
6473 tokio:: spawn ( async move {
6574 let mut matches = 0 ;
75+ let mut batch = Vec :: new ( ) ;
76+ let mut batch_interval = time:: interval ( SEARCH_RESULT_BATCH_INTERVAL ) ;
77+ batch_interval. set_missed_tick_behavior ( MissedTickBehavior :: Skip ) ;
78+ batch_interval. tick ( ) . await ;
79+
6680 // In cancel case, the loop will be ended automatically
67- while let Some ( file_result) = result_rx. recv ( ) . await {
68- let _ = socket. emit ( "search:result" , & file_result) ;
69- matches += file_result. matches . len ( ) ;
81+ loop {
82+ tokio:: select! {
83+ maybe_file_result = result_rx. recv( ) => {
84+ match maybe_file_result {
85+ Some ( file_result) => {
86+ matches += file_result. matches. len( ) ;
87+ batch. push( file_result) ;
88+ }
89+ None => break ,
90+ }
91+ }
92+ _ = batch_interval. tick( ) => {
93+ if !batch. is_empty( ) {
94+ let results = std:: mem:: take( & mut batch) ;
95+ let _ = socket. emit( "search:results" , & SearchResultsBatch { results } ) ;
96+ }
97+ }
98+ }
99+ }
100+
101+ if !batch. is_empty ( ) {
102+ let results = std:: mem:: take ( & mut batch) ;
103+ let _ = socket. emit ( "search:results" , & SearchResultsBatch { results } ) ;
70104 }
71105
72106 let _ = socket. emit (
@@ -95,5 +129,6 @@ pub async fn handle_search_cancel(socket: SocketRef, state: State<AppState>) {
95129 // Clear the cancel token
96130 data. search_cancel = None ;
97131 data. search_pattern = None ;
132+ data. search_last_file_result = None ;
98133 }
99134}
0 commit comments