From 6fa2e62fa41175668fb62479063117682c9ecde9 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 30 Aug 2022 16:29:20 -0400 Subject: [PATCH] Start asking Editors to update git after a debounced delay --- crates/editor/src/items.rs | 9 ++ crates/workspace/src/workspace.rs | 132 ++++++++++++++++++++++++------ 2 files changed, 115 insertions(+), 26 deletions(-) diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index f63ffc3d7c..22a069c5c0 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -478,6 +478,15 @@ impl Item for Editor { }) } + fn update_git( + &mut self, + _project: ModelHandle, + _cx: &mut ViewContext, + ) -> Task> { + println!("Editor::update_git"); + Task::ready(Ok(())) + } + fn to_item_events(event: &Self::Event) -> Vec { let mut result = Vec::new(); match event { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b9cface656..3446dc0f0e 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -52,7 +52,6 @@ use std::{ cell::RefCell, fmt, future::Future, - mem, ops::Range, path::{Path, PathBuf}, rc::Rc, @@ -318,7 +317,23 @@ pub trait Item: View { project: ModelHandle, cx: &mut ViewContext, ) -> Task>; + fn update_git( + &mut self, + _project: ModelHandle, + _cx: &mut ViewContext, + ) -> Task> { + Task::ready(Ok(())) + } fn to_item_events(event: &Self::Event) -> Vec; + fn should_close_item_on_event(_: &Self::Event) -> bool { + false + } + fn should_update_tab_on_event(_: &Self::Event) -> bool { + false + } + fn is_edit_event(_: &Self::Event) -> bool { + false + } fn act_as_type( &self, type_id: TypeId, @@ -435,6 +450,57 @@ impl FollowableItemHandle for ViewHandle { } } +struct DelayedDebouncedEditAction { + task: Option>, + cancel_channel: Option>, +} + +impl DelayedDebouncedEditAction { + fn new() -> DelayedDebouncedEditAction { + DelayedDebouncedEditAction { + task: None, + cancel_channel: None, + } + } + + fn fire_new( + &mut self, + delay: Duration, + workspace: &Workspace, + cx: &mut ViewContext, + f: F, + ) where + F: FnOnce(ModelHandle, AsyncAppContext) -> Fut + 'static, + Fut: 'static + Future, + { + if let Some(channel) = self.cancel_channel.take() { + _ = channel.send(()); + } + + let project = workspace.project().downgrade(); + + let (sender, mut receiver) = oneshot::channel::<()>(); + self.cancel_channel = Some(sender); + + let previous_task = self.task.take(); + self.task = Some(cx.spawn_weak(|_, cx| async move { + let mut timer = cx.background().timer(delay).fuse(); + if let Some(previous_task) = previous_task { + previous_task.await; + } + + futures::select_biased! { + _ = receiver => return, + _ = timer => {} + } + + if let Some(project) = project.upgrade(&cx) { + (f)(project, cx).await; + } + })); + } +} + pub trait ItemHandle: 'static + fmt::Debug { fn subscribe_to_item_events( &self, @@ -473,6 +539,11 @@ pub trait ItemHandle: 'static + fmt::Debug { ) -> Task>; fn reload(&self, project: ModelHandle, cx: &mut MutableAppContext) -> Task>; + fn update_git( + &self, + project: ModelHandle, + cx: &mut MutableAppContext, + ) -> Task>; fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option; fn to_followable_item_handle(&self, cx: &AppContext) -> Option>; fn on_release( @@ -578,8 +649,8 @@ impl ItemHandle for ViewHandle { .insert(self.id(), pane.downgrade()) .is_none() { - let mut pending_autosave = None; - let mut cancel_pending_autosave = oneshot::channel::<()>().0; + let mut pending_autosave = DelayedDebouncedEditAction::new(); + let mut pending_git_update = DelayedDebouncedEditAction::new(); let pending_update = Rc::new(RefCell::new(None)); let pending_update_scheduled = Rc::new(AtomicBool::new(false)); @@ -637,45 +708,46 @@ impl ItemHandle for ViewHandle { .detach_and_log_err(cx); return; } + ItemEvent::UpdateTab => { pane.update(cx, |_, cx| { cx.emit(pane::Event::ChangeItemTitle); cx.notify(); }); } + ItemEvent::Edit => { if let Autosave::AfterDelay { milliseconds } = cx.global::().autosave { - let prev_autosave = pending_autosave - .take() - .unwrap_or_else(|| Task::ready(Some(()))); - let (cancel_tx, mut cancel_rx) = oneshot::channel::<()>(); - let prev_cancel_tx = - mem::replace(&mut cancel_pending_autosave, cancel_tx); - let project = workspace.project.downgrade(); - let _ = prev_cancel_tx.send(()); + let delay = Duration::from_millis(milliseconds); let item = item.clone(); - pending_autosave = - Some(cx.spawn_weak(|_, mut cx| async move { - let mut timer = cx - .background() - .timer(Duration::from_millis(milliseconds)) - .fuse(); - prev_autosave.await; - futures::select_biased! { - _ = cancel_rx => return None, - _ = timer => {} - } - - let project = project.upgrade(&cx)?; + pending_autosave.fire_new( + delay, + workspace, + cx, + |project, mut cx| async move { cx.update(|cx| Pane::autosave_item(&item, project, cx)) .await .log_err(); - None - })); + }, + ); } + + const GIT_DELAY: Duration = Duration::from_millis(800); + let item = item.clone(); + pending_git_update.fire_new( + GIT_DELAY, + workspace, + cx, + |project, mut cx| async move { + cx.update(|cx| item.update_git(project, cx)) + .await + .log_err(); + }, + ); } + _ => {} } } @@ -755,6 +827,14 @@ impl ItemHandle for ViewHandle { self.update(cx, |item, cx| item.reload(project, cx)) } + fn update_git( + &self, + project: ModelHandle, + cx: &mut MutableAppContext, + ) -> Task> { + self.update(cx, |item, cx| item.update_git(project, cx)) + } + fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option { self.read(cx).act_as_type(type_id, self, cx) }