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}