sql_cli/utils/debouncer.rs
1use std::time::{Duration, Instant};
2
3/// A simple debouncer that tracks when an action should be triggered
4/// after a period of inactivity
5#[derive(Debug, Clone)]
6pub struct Debouncer {
7 /// The duration to wait after the last event before triggering
8 delay: Duration,
9 /// When the last event occurred
10 last_event: Option<Instant>,
11 /// Whether we have a pending trigger
12 pending: bool,
13}
14
15impl Debouncer {
16 /// Create a new debouncer with the specified delay in milliseconds
17 #[must_use]
18 pub fn new(delay_ms: u64) -> Self {
19 Self {
20 delay: Duration::from_millis(delay_ms),
21 last_event: None,
22 pending: false,
23 }
24 }
25
26 /// Register that an event occurred
27 pub fn trigger(&mut self) {
28 self.last_event = Some(Instant::now());
29 self.pending = true;
30 }
31
32 /// Check if enough time has passed to execute the debounced action
33 /// Returns true if the action should be executed
34 pub fn should_execute(&mut self) -> bool {
35 if !self.pending {
36 return false;
37 }
38
39 if let Some(last) = self.last_event {
40 if last.elapsed() >= self.delay {
41 self.pending = false;
42 self.last_event = None;
43 return true;
44 }
45 }
46 false
47 }
48
49 /// Get the time remaining before the action will trigger
50 /// Returns None if no action is pending
51 #[must_use]
52 pub fn time_remaining(&self) -> Option<Duration> {
53 if !self.pending {
54 return None;
55 }
56
57 self.last_event.map(|last| {
58 let elapsed = last.elapsed();
59 if elapsed >= self.delay {
60 Duration::from_millis(0)
61 } else {
62 self.delay - elapsed
63 }
64 })
65 }
66
67 /// Reset the debouncer, canceling any pending action
68 pub fn reset(&mut self) {
69 self.last_event = None;
70 self.pending = false;
71 }
72
73 /// Check if there's a pending action
74 #[must_use]
75 pub fn is_pending(&self) -> bool {
76 self.pending
77 }
78}
79
80/// Trait for widgets that support debounced input
81pub trait DebouncedInput {
82 /// Called when input changes but should be debounced
83 fn on_input_changed(&mut self);
84
85 /// Called when the debounce timer expires and action should be taken
86 fn on_debounced_execute(&mut self);
87
88 /// Check if debouncing should trigger execution
89 fn check_debounce(&mut self) -> bool;
90}