1use futures::{FutureExt, channel::oneshot};
 2use gpui::{Context, Task};
 3use std::{marker::PhantomData, time::Duration};
 4
 5pub struct DebouncedDelay<E: 'static> {
 6    task: Option<Task<()>>,
 7    cancel_channel: Option<oneshot::Sender<()>>,
 8    _phantom_data: PhantomData<E>,
 9}
10
11impl<E: 'static> Default for DebouncedDelay<E> {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl<E: 'static> DebouncedDelay<E> {
18    pub fn new() -> Self {
19        Self {
20            task: None,
21            cancel_channel: None,
22            _phantom_data: PhantomData,
23        }
24    }
25
26    pub fn fire_new<F>(&mut self, delay: Duration, cx: &mut Context<E>, func: F)
27    where
28        F: 'static + Send + FnOnce(&mut E, &mut Context<E>) -> Task<()>,
29    {
30        if let Some(channel) = self.cancel_channel.take() {
31            _ = channel.send(());
32        }
33
34        let (sender, mut receiver) = oneshot::channel::<()>();
35        self.cancel_channel = Some(sender);
36
37        let previous_task = self.task.take();
38        self.task = Some(cx.spawn(async move |entity, cx| {
39            let mut timer = cx.background_executor().timer(delay).fuse();
40            if let Some(previous_task) = previous_task {
41                previous_task.await;
42            }
43
44            futures::select_biased! {
45                _ = receiver => return,
46                _ = timer => {}
47            }
48
49            if let Ok(task) = entity.update(cx, |project, cx| (func)(project, cx)) {
50                task.await;
51            }
52        }));
53    }
54}