Move more window methods off AsyncAppContext

Nathan Sobo created

Change summary

crates/collab_ui/src/contact_list.rs          |  4 
crates/command_palette/src/command_palette.rs | 13 ++-
crates/context_menu/src/context_menu.rs       | 14 +++
crates/gpui/src/app.rs                        | 71 +++++++++-----------
crates/search/src/project_search.rs           | 12 +-
crates/workspace/src/dock.rs                  |  7 +
crates/workspace/src/workspace.rs             | 12 +-
crates/zed/src/zed.rs                         |  4 
8 files changed, 73 insertions(+), 64 deletions(-)

Detailed changes

crates/collab_ui/src/contact_list.rs 🔗

@@ -312,11 +312,11 @@ impl ContactList {
                     .update(&mut cx, |store, cx| store.remove_contact(user_id, cx))
                     .await
                 {
-                    cx.prompt(
-                        window,
+                    window.prompt(
                         PromptLevel::Info,
                         &format!("Failed to remove contact: {}", e),
                         &["Ok"],
+                        &mut cx,
                     );
                 }
             }

crates/command_palette/src/command_palette.rs 🔗

@@ -1,8 +1,8 @@
 use collections::CommandPaletteFilter;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
-    actions, elements::*, keymap_matcher::Keystroke, Action, AnyWindowHandle, AppContext, Element,
-    MouseState, ViewContext,
+    actions, anyhow::anyhow, elements::*, keymap_matcher::Keystroke, Action, AnyWindowHandle,
+    AppContext, Element, MouseState, ViewContext,
 };
 use picker::{Picker, PickerDelegate, PickerEvent};
 use std::cmp;
@@ -83,9 +83,10 @@ impl PickerDelegate for CommandPaletteDelegate {
         let view_id = self.focused_view_id;
         let window = cx.window();
         cx.spawn(move |picker, mut cx| async move {
-            let actions = cx
-                .available_actions(window, view_id)
+            let actions = window
+                .available_actions(view_id, &cx)
                 .into_iter()
+                .flatten()
                 .filter_map(|(name, action, bindings)| {
                     let filtered = cx.read(|cx| {
                         if cx.has_global::<CommandPaletteFilter>() {
@@ -168,7 +169,9 @@ impl PickerDelegate for CommandPaletteDelegate {
             let action = self.actions.remove(action_ix).action;
             cx.app_context()
                 .spawn(move |mut cx| async move {
-                    cx.dispatch_action(window, focused_view_id, action.as_ref())
+                    window
+                        .dispatch_action(focused_view_id, action.as_ref(), &mut cx)
+                        .ok_or_else(|| anyhow!("window was closed"))
                 })
                 .detach_and_log_err(cx);
         }

crates/context_menu/src/context_menu.rs 🔗

@@ -1,5 +1,5 @@
 use gpui::{
-    anyhow,
+    anyhow::{self, anyhow},
     elements::*,
     geometry::vector::Vector2F,
     keymap_matcher::KeymapContext,
@@ -223,7 +223,9 @@ impl ContextMenu {
                         let action = action.boxed_clone();
                         cx.app_context()
                             .spawn(|mut cx| async move {
-                                cx.dispatch_action(window, view_id, action.as_ref())
+                                window
+                                    .dispatch_action(view_id, action.as_ref(), &mut cx)
+                                    .ok_or_else(|| anyhow!("window was closed"))
                             })
                             .detach_and_log_err(cx);
                     }
@@ -486,7 +488,13 @@ impl ContextMenu {
                                         let action = action.boxed_clone();
                                         cx.app_context()
                                             .spawn(|mut cx| async move {
-                                                cx.dispatch_action(window, view_id, action.as_ref())
+                                                window
+                                                    .dispatch_action(
+                                                        view_id,
+                                                        action.as_ref(),
+                                                        &mut cx,
+                                                    )
+                                                    .ok_or_else(|| anyhow!("window was closed"))
                                             })
                                             .detach_and_log_err(cx);
                                     }

crates/gpui/src/app.rs 🔗

@@ -344,29 +344,6 @@ impl AsyncAppContext {
         self.0.borrow().windows().collect()
     }
 
-    pub fn dispatch_action(
-        &mut self,
-        window: AnyWindowHandle,
-        view_id: usize,
-        action: &dyn Action,
-    ) -> Result<()> {
-        self.0
-            .borrow_mut()
-            .update_window(window, |cx| {
-                cx.dispatch_action(Some(view_id), action);
-            })
-            .ok_or_else(|| anyhow!("window not found"))
-    }
-
-    pub fn available_actions(
-        &self,
-        window: AnyWindowHandle,
-        view_id: usize,
-    ) -> Vec<(&'static str, Box<dyn Action>, SmallVec<[Binding; 1]>)> {
-        self.read_window(window, |cx| cx.available_actions(view_id))
-            .unwrap_or_default()
-    }
-
     pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
     where
         T: Entity,
@@ -387,21 +364,6 @@ impl AsyncAppContext {
         self.update(|cx| cx.add_window(window_options, build_root_view))
     }
 
-    pub fn activate_window(&mut self, window: AnyWindowHandle) {
-        self.update_window(window, |cx| cx.activate_window());
-    }
-
-    // TODO: Can we eliminate this method and move it to WindowContext then call it with update_window?s
-    pub fn prompt(
-        &mut self,
-        window: AnyWindowHandle,
-        level: PromptLevel,
-        msg: &str,
-        answers: &[&str],
-    ) -> Option<oneshot::Receiver<usize>> {
-        self.update_window(window, |cx| cx.prompt(level, msg, answers))
-    }
-
     pub fn platform(&self) -> Arc<dyn Platform> {
         self.0.borrow().platform().clone()
     }
@@ -4060,6 +4022,39 @@ impl AnyWindowHandle {
         })
     }
 
+    pub fn activate<C: BorrowWindowContext>(&mut self, cx: &mut C) -> C::Result<()> {
+        self.update(cx, |cx| cx.activate_window())
+    }
+
+    pub fn prompt<C: BorrowWindowContext>(
+        &self,
+        level: PromptLevel,
+        msg: &str,
+        answers: &[&str],
+        cx: &mut C,
+    ) -> C::Result<oneshot::Receiver<usize>> {
+        self.update(cx, |cx| cx.prompt(level, msg, answers))
+    }
+
+    pub fn dispatch_action<C: BorrowWindowContext>(
+        &self,
+        view_id: usize,
+        action: &dyn Action,
+        cx: &mut C,
+    ) -> C::Result<()> {
+        self.update(cx, |cx| {
+            cx.dispatch_action(Some(view_id), action);
+        })
+    }
+
+    pub fn available_actions<C: BorrowWindowContext>(
+        &self,
+        view_id: usize,
+        cx: &C,
+    ) -> C::Result<Vec<(&'static str, Box<dyn Action>, SmallVec<[Binding; 1]>)>> {
+        self.read_with(cx, |cx| cx.available_actions(view_id))
+    }
+
     #[cfg(any(test, feature = "test-support"))]
     pub fn simulate_activation(&self, cx: &mut TestAppContext) {
         self.update(cx, |cx| {

crates/search/src/project_search.rs 🔗

@@ -1599,7 +1599,7 @@ pub mod tests {
         let search_view_id = search_view.id();
 
         cx.spawn(|mut cx| async move {
-            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+            window.dispatch_action(search_view_id, &ToggleFocus, &mut cx);
         })
         .detach();
         deterministic.run_until_parked();
@@ -1650,9 +1650,9 @@ pub mod tests {
                 "Search view should be focused after mismatching query had been used in search",
             );
         });
-        cx.spawn(|mut cx| async move {
-            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
-        })
+        cx.spawn(
+            |mut cx| async move { window.dispatch_action(search_view_id, &ToggleFocus, &mut cx) },
+        )
         .detach();
         deterministic.run_until_parked();
         search_view.update(cx, |search_view, cx| {
@@ -1683,7 +1683,7 @@ pub mod tests {
             );
         });
         cx.spawn(|mut cx| async move {
-            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+            window.dispatch_action(search_view_id, &ToggleFocus, &mut cx);
         })
         .detach();
         deterministic.run_until_parked();
@@ -1713,7 +1713,7 @@ pub mod tests {
         });
 
         cx.spawn(|mut cx| async move {
-            cx.dispatch_action(window.into(), search_view_id, &ToggleFocus)
+            window.dispatch_action(search_view_id, &ToggleFocus, &mut cx);
         })
         .detach();
         deterministic.run_until_parked();

crates/workspace/src/dock.rs 🔗

@@ -534,8 +534,11 @@ impl View for PanelButtons {
                                         let view_id = this.workspace.id();
                                         let tooltip_action = tooltip_action.boxed_clone();
                                         cx.spawn(|_, mut cx| async move {
-                                            cx.dispatch_action(window, view_id, &*tooltip_action)
-                                                .ok();
+                                            window.dispatch_action(
+                                                view_id,
+                                                &*tooltip_action,
+                                                &mut cx,
+                                            );
                                         })
                                         .detach();
                                     }

crates/workspace/src/workspace.rs 🔗

@@ -1280,11 +1280,11 @@ impl Workspace {
                     && workspace_count == 1
                     && active_call.read_with(&cx, |call, _| call.room().is_some())
                 {
-                    let answer = cx.prompt(
-                        window,
+                    let answer = window.prompt(
                         PromptLevel::Warning,
                         "Do you want to leave the current call?",
                         &["Close window and hang up", "Cancel"],
+                        &mut cx,
                     );
 
                     if let Some(mut answer) = answer {
@@ -4000,7 +4000,7 @@ pub fn join_remote_project(
             workspace.downgrade()
         };
 
-        cx.activate_window(workspace.window());
+        workspace.window().activate(&mut cx);
         cx.platform().activate(true);
 
         workspace.update(&mut cx, |workspace, cx| {
@@ -4049,12 +4049,12 @@ pub fn restart(_: &Restart, cx: &mut AppContext) {
         // prompt in the active window before switching to a different window.
         workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
 
-        if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) {
-            let answer = cx.prompt(
-                window.into(),
+        if let (true, Some(window)) = (should_confirm, workspace_windows.first()) {
+            let answer = window.prompt(
                 PromptLevel::Info,
                 "Are you sure you want to restart?",
                 &["Restart", "Cancel"],
+                &mut cx,
             );
 
             if let Some(mut answer) = answer {

crates/zed/src/zed.rs 🔗

@@ -416,11 +416,11 @@ fn quit(_: &Quit, cx: &mut gpui::AppContext) {
         workspace_windows.sort_by_key(|window| window.is_active(&cx) == Some(false));
 
         if let (true, Some(window)) = (should_confirm, workspace_windows.first().copied()) {
-            let answer = cx.prompt(
-                window.into(),
+            let answer = window.prompt(
                 PromptLevel::Info,
                 "Are you sure you want to quit?",
                 &["Quit", "Cancel"],
+                &mut cx,
             );
 
             if let Some(mut answer) = answer {