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    pub fn new(delay_ms: u64) -> Self {
18        Self {
19            delay: Duration::from_millis(delay_ms),
20            last_event: None,
21            pending: false,
22        }
23    }
24
25    /// Register that an event occurred
26    pub fn trigger(&mut self) {
27        self.last_event = Some(Instant::now());
28        self.pending = true;
29    }
30
31    /// Check if enough time has passed to execute the debounced action
32    /// Returns true if the action should be executed
33    pub fn should_execute(&mut self) -> bool {
34        if !self.pending {
35            return false;
36        }
37
38        if let Some(last) = self.last_event {
39            if last.elapsed() >= self.delay {
40                self.pending = false;
41                self.last_event = None;
42                return true;
43            }
44        }
45        false
46    }
47
48    /// Get the time remaining before the action will trigger
49    /// Returns None if no action is pending
50    pub fn time_remaining(&self) -> Option<Duration> {
51        if !self.pending {
52            return None;
53        }
54
55        self.last_event.map(|last| {
56            let elapsed = last.elapsed();
57            if elapsed >= self.delay {
58                Duration::from_millis(0)
59            } else {
60                self.delay - elapsed
61            }
62        })
63    }
64
65    /// Reset the debouncer, canceling any pending action
66    pub fn reset(&mut self) {
67        self.last_event = None;
68        self.pending = false;
69    }
70
71    /// Check if there's a pending action
72    pub fn is_pending(&self) -> bool {
73        self.pending
74    }
75}
76
77/// Trait for widgets that support debounced input
78pub trait DebouncedInput {
79    /// Called when input changes but should be debounced
80    fn on_input_changed(&mut self);
81
82    /// Called when the debounce timer expires and action should be taken
83    fn on_debounced_execute(&mut self);
84
85    /// Check if debouncing should trigger execution
86    fn check_debounce(&mut self) -> bool;
87}