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}