@@ -120,6 +120,7 @@ const SUBCOMMANDS: &[&str] = &[
120120
121121/// Prefix used to search user saved applications.
122122pub const APP_PREFIX : & str = "app" ;
123+ const NOTE_SEARCH_DEBOUNCE : Duration = Duration :: from_secs ( 1 ) ;
123124
124125fn scale_ui < R > ( ui : & mut egui:: Ui , scale : f32 , add_contents : impl FnOnce ( & mut egui:: Ui ) -> R ) -> R {
125126 ui. scope ( |ui| {
@@ -518,6 +519,7 @@ pub struct LauncherApp {
518519 last_results_valid : bool ,
519520 last_timer_query : bool ,
520521 last_stopwatch_query : bool ,
522+ last_note_search_change : Option < Instant > ,
521523 pending_query : Option < String > ,
522524 confirm_modal : ConfirmationModal ,
523525 pending_confirm : Option < PendingConfirmAction > ,
@@ -714,6 +716,39 @@ impl LauncherApp {
714716 }
715717 }
716718
719+ fn is_note_search_query ( query : & str ) -> bool {
720+ query
721+ . trim_start ( )
722+ . to_lowercase ( )
723+ . starts_with ( "note search" )
724+ }
725+
726+ fn note_search_debounce_ready (
727+ last_change : Option < Instant > ,
728+ now : Instant ,
729+ debounce : Duration ,
730+ ) -> bool {
731+ last_change
732+ . map ( |changed_at| now. duration_since ( changed_at) >= debounce)
733+ . unwrap_or ( false )
734+ }
735+
736+ fn maybe_run_note_search_debounce ( & mut self ) {
737+ if !Self :: is_note_search_query ( & self . query ) {
738+ self . last_note_search_change = None ;
739+ return ;
740+ }
741+
742+ if Self :: note_search_debounce_ready (
743+ self . last_note_search_change ,
744+ Instant :: now ( ) ,
745+ NOTE_SEARCH_DEBOUNCE ,
746+ ) {
747+ self . search ( ) ;
748+ self . last_note_search_change = None ;
749+ }
750+ }
751+
717752 pub fn plugin_enabled ( & self , name : & str ) -> bool {
718753 match & self . enabled_plugins {
719754 Some ( set) => set. contains ( name) ,
@@ -1315,6 +1350,7 @@ impl LauncherApp {
13151350 last_results_valid : false ,
13161351 last_timer_query : false ,
13171352 last_stopwatch_query : false ,
1353+ last_note_search_change : None ,
13181354 pending_query : None ,
13191355 confirm_modal : ConfirmationModal :: default ( ) ,
13201356 pending_confirm : None ,
@@ -3477,6 +3513,7 @@ impl eframe::App for LauncherApp {
34773513 self . search ( ) ;
34783514 self . focus_input ( ) ;
34793515 }
3516+ self . maybe_run_note_search_debounce ( ) ;
34803517 if let ( Some ( t) , Some ( _) ) = ( self . error_time , self . error . as_ref ( ) ) {
34813518 if t. elapsed ( ) . as_secs_f32 ( ) >= 3.0 {
34823519 self . error = None ;
@@ -3690,7 +3727,12 @@ impl eframe::App for LauncherApp {
36903727
36913728 if input. changed ( ) {
36923729 self . autocomplete_index = 0 ;
3693- self . search ( ) ;
3730+ if Self :: is_note_search_query ( & self . query ) {
3731+ self . last_note_search_change = Some ( Instant :: now ( ) ) ;
3732+ } else {
3733+ self . last_note_search_change = None ;
3734+ self . search ( ) ;
3735+ }
36943736 }
36953737
36963738 if self . query_autocomplete && !use_dashboard && !self . suggestions . is_empty ( ) {
@@ -4854,6 +4896,7 @@ mod tests {
48544896 Arc , Mutex ,
48554897 } ;
48564898 use tempfile:: tempdir;
4899+ use std:: time:: { Duration , Instant } ;
48574900
48584901 static TEST_MUTEX : Lazy < Mutex < ( ) > > = Lazy :: new ( || Mutex :: new ( ( ) ) ) ;
48594902
@@ -5148,4 +5191,24 @@ mod tests {
51485191
51495192 std:: env:: set_current_dir ( orig_dir) . unwrap ( ) ;
51505193 }
5194+
5195+ #[ test]
5196+ fn note_search_debounce_respects_delay ( ) {
5197+ let start = Instant :: now ( ) ;
5198+ assert ! ( !LauncherApp :: note_search_debounce_ready(
5199+ Some ( start) ,
5200+ start,
5201+ NOTE_SEARCH_DEBOUNCE ,
5202+ ) ) ;
5203+ assert ! ( !LauncherApp :: note_search_debounce_ready(
5204+ Some ( start) ,
5205+ start + Duration :: from_millis( 999 ) ,
5206+ NOTE_SEARCH_DEBOUNCE ,
5207+ ) ) ;
5208+ assert ! ( LauncherApp :: note_search_debounce_ready(
5209+ Some ( start) ,
5210+ start + NOTE_SEARCH_DEBOUNCE ,
5211+ NOTE_SEARCH_DEBOUNCE ,
5212+ ) ) ;
5213+ }
51515214}
0 commit comments