1use futures::{channel::oneshot, FutureExt};
2use gpui::{ModelContext, 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> DebouncedDelay<E> {
12 pub fn new() -> Self {
13 Self {
14 task: None,
15 cancel_channel: None,
16 _phantom_data: PhantomData,
17 }
18 }
19
20 pub fn fire_new<F>(&mut self, delay: Duration, cx: &mut ModelContext<E>, func: F)
21 where
22 F: 'static + Send + FnOnce(&mut E, &mut ModelContext<E>) -> Task<()>,
23 {
24 if let Some(channel) = self.cancel_channel.take() {
25 _ = channel.send(());
26 }
27
28 let (sender, mut receiver) = oneshot::channel::<()>();
29 self.cancel_channel = Some(sender);
30
31 let previous_task = self.task.take();
32 self.task = Some(cx.spawn(move |model, mut cx| async move {
33 let mut timer = cx.background_executor().timer(delay).fuse();
34 if let Some(previous_task) = previous_task {
35 previous_task.await;
36 }
37
38 futures::select_biased! {
39 _ = receiver => return,
40 _ = timer => {}
41 }
42
43 if let Ok(task) = model.update(&mut cx, |project, cx| (func)(project, cx)) {
44 task.await;
45 }
46 }));
47 }
48}