From dbaa6366834790cda0bd92ea8971fec9ae9b601b Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 19 Jul 2024 03:44:55 -0500 Subject: [PATCH] Picker: Skip dynamic query debounce for pastes (#11211) Pastes are probably the last edit one means to make before the query should run so it doesn't need to be debounced. This makes global search much snappier for example when accepting the history suggestion from the '/' register or pasting a pattern from the clipboard or a register. --- helix-term/src/ui/picker.rs | 24 +++++++++++++++++------- helix-term/src/ui/picker/handlers.rs | 17 ++++++++++++++--- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index ffec0fd83..118dafa77 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -52,7 +52,7 @@ use helix_view::{ Document, DocumentId, Editor, }; -use self::handlers::{DynamicQueryHandler, PreviewHighlightHandler}; +use self::handlers::{DynamicQueryChange, DynamicQueryHandler, PreviewHighlightHandler}; pub const ID: &str = "picker"; @@ -272,7 +272,7 @@ pub struct Picker { file_fn: Option>, /// An event handler for syntax highlighting the currently previewed file. preview_highlight_handler: Sender>, - dynamic_query_handler: Option>>, + dynamic_query_handler: Option>, } impl Picker { @@ -435,7 +435,12 @@ impl Picker { debounce_ms: Option, ) -> Self { let handler = DynamicQueryHandler::new(callback, debounce_ms).spawn(); - helix_event::send_blocking(&handler, self.primary_query()); + let event = DynamicQueryChange { + query: self.primary_query(), + // Treat the initial query as a paste. + is_paste: true, + }; + helix_event::send_blocking(&handler, event); self.dynamic_query_handler = Some(handler); self } @@ -511,12 +516,12 @@ impl Picker { fn prompt_handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult { if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) { - self.handle_prompt_change(); + self.handle_prompt_change(matches!(event, Event::Paste(_))); } EventResult::Consumed(None) } - fn handle_prompt_change(&mut self) { + fn handle_prompt_change(&mut self, is_paste: bool) { // TODO: better track how the pattern has changed let line = self.prompt.line(); let old_query = self.query.parse(line); @@ -557,7 +562,11 @@ impl Picker { // If this is a dynamic picker, notify the query hook that the primary // query might have been updated. if let Some(handler) = &self.dynamic_query_handler { - helix_event::send_blocking(handler, self.primary_query()); + let event = DynamicQueryChange { + query: self.primary_query(), + is_paste, + }; + helix_event::send_blocking(handler, event); } } @@ -1028,7 +1037,8 @@ impl Component for Picker AsyncHook } } +pub(super) struct DynamicQueryChange { + pub query: Arc, + pub is_paste: bool, +} + pub(super) struct DynamicQueryHandler { callback: Arc>, // Duration used as a debounce. @@ -137,9 +142,10 @@ impl DynamicQueryHandler AsyncHook for DynamicQueryHandler { - type Event = Arc; + type Event = DynamicQueryChange; - fn handle_event(&mut self, query: Self::Event, _timeout: Option) -> Option { + fn handle_event(&mut self, change: Self::Event, _timeout: Option) -> Option { + let DynamicQueryChange { query, is_paste } = change; if query == self.last_query { // If the search query reverts to the last one we requested, no need to // make a new request. @@ -147,7 +153,12 @@ impl AsyncHook for DynamicQu None } else { self.query = Some(query); - Some(Instant::now() + self.debounce) + if is_paste { + self.finish_debounce(); + None + } else { + Some(Instant::now() + self.debounce) + } } }