WIP

Antonio Scandurra created

Change summary

crates/gpui2/src/app.rs                    |  8 -
crates/gpui2/src/app/model_context.rs      |  5 -
crates/gpui2/src/window.rs                 | 12 +--
crates/workspace2/src/persistence/model.rs | 14 ++-
crates/workspace2/src/workspace2.rs        | 89 +++++++++++------------
5 files changed, 56 insertions(+), 72 deletions(-)

Detailed changes

crates/gpui2/src/app.rs 🔗

@@ -504,16 +504,12 @@ impl AppContext {
 
     /// Spawns the future returned by the given function on the thread pool. The closure will be invoked
     /// with AsyncAppContext, which allows the application state to be accessed across await points.
-    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
+    pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task<R>
     where
         Fut: Future<Output = R> + Send + 'static,
         R: Send + 'static,
     {
-        let cx = self.to_async();
-        self.executor.spawn(async move {
-            let future = f(cx);
-            future.await
-        })
+        self.executor.spawn(f(self.to_async()))
     }
 
     /// Schedules the given function to be run at the end of the current effect cycle, allowing entities

crates/gpui2/src/app/model_context.rs 🔗

@@ -189,10 +189,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
         result
     }
 
-    pub fn spawn<Fut, R>(
-        &self,
-        f: impl FnOnce(WeakModel<T>, AsyncAppContext) -> Fut + Send + 'static,
-    ) -> Task<R>
+    pub fn spawn<Fut, R>(&self, f: impl FnOnce(WeakModel<T>, AsyncAppContext) -> Fut) -> Task<R>
     where
         T: 'static,
         Fut: Future<Output = R> + Send + 'static,

crates/gpui2/src/window.rs 🔗

@@ -484,7 +484,7 @@ impl<'a> WindowContext<'a> {
     /// use within your future.
     pub fn spawn<Fut, R>(
         &mut self,
-        f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut + Send + 'static,
+        f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut,
     ) -> Task<R>
     where
         R: Send + 'static,
@@ -493,8 +493,7 @@ impl<'a> WindowContext<'a> {
         let window = self.window.handle;
         self.app.spawn(move |app| {
             let cx = AsyncWindowContext::new(app, window);
-            let future = f(window, cx);
-            async move { future.await }
+            f(window, cx)
         })
     }
 
@@ -1872,17 +1871,14 @@ impl<'a, V: 'static> ViewContext<'a, V> {
 
     pub fn spawn<Fut, R>(
         &mut self,
-        f: impl FnOnce(WeakView<V>, AsyncWindowContext) -> Fut + Send + 'static,
+        f: impl FnOnce(WeakView<V>, AsyncWindowContext) -> Fut,
     ) -> Task<R>
     where
         R: Send + 'static,
         Fut: Future<Output = R> + Send + 'static,
     {
         let view = self.view().downgrade();
-        self.window_cx.spawn(move |_, cx| {
-            let result = f(view, cx);
-            async move { result.await }
-        })
+        self.window_cx.spawn(move |_, cx| f(view, cx))
     }
 
     pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R

crates/workspace2/src/persistence/model.rs 🔗

@@ -7,7 +7,9 @@ use db2::sqlez::{
     bindable::{Bind, Column, StaticColumnCount},
     statement::Statement,
 };
-use gpui2::{AsyncWindowContext, Model, Task, View, WeakView, WindowBounds};
+use gpui2::{
+    AsyncAppContext, AsyncWindowContext, Model, Task, View, WeakView, WindowBounds, WindowHandle,
+};
 use project2::Project;
 use std::{
     path::{Path, PathBuf},
@@ -153,8 +155,8 @@ impl SerializedPaneGroup {
         self,
         project: &Model<Project>,
         workspace_id: WorkspaceId,
-        workspace: &WeakView<Workspace>,
-        cx: &mut AsyncWindowContext,
+        workspace: WindowHandle<Workspace>,
+        cx: &mut AsyncAppContext,
     ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
         match self {
             SerializedPaneGroup::Group {
@@ -231,8 +233,8 @@ impl SerializedPane {
         project: &Model<Project>,
         pane: &WeakView<Pane>,
         workspace_id: WorkspaceId,
-        workspace: &WeakView<Workspace>,
-        cx: &mut AsyncWindowContext,
+        workspace: WindowHandle<Workspace>,
+        cx: &mut AsyncAppContext,
     ) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
         let mut items = Vec::new();
         let mut active_item_index = None;
@@ -241,7 +243,7 @@ impl SerializedPane {
             let item_handle = pane
                 .update(cx, |_, cx| {
                     if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
-                        deserializer(project, workspace.clone(), workspace_id, item.item_id, cx)
+                        deserializer(project, workspace, workspace_id, item.item_id, cx)
                     } else {
                         Task::ready(Err(anyhow::anyhow!(
                             "Deserializer does not exist for item kind: {}",

crates/workspace2/src/workspace2.rs 🔗

@@ -29,9 +29,9 @@ use futures::{
 };
 use gpui2::{
     div, point, size, AnyModel, AnyView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds,
-    Context, Div, EventEmitter, GlobalPixels, MainThread, Model, ModelContext, Point, Render, Size,
-    Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext,
-    WindowHandle, WindowOptions,
+    Context, Div, Entity, EventEmitter, GlobalPixels, MainThread, Model, ModelContext, Point,
+    Render, Size, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
+    WindowContext, WindowHandle, WindowOptions,
 };
 use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
 use language2::LanguageRegistry;
@@ -399,7 +399,7 @@ type ItemDeserializers = HashMap<
     Arc<str>,
     fn(
         Model<Project>,
-        WeakView<Workspace>,
+        WindowHandle<Workspace>,
         WorkspaceId,
         ItemId,
         &mut ViewContext<Pane>,
@@ -891,19 +891,22 @@ impl Workspace {
 
             window.update(&mut cx, |_, cx| cx.activate_window());
 
-            let workspace = workspace.downgrade();
-            notify_if_database_failed(&workspace, &mut cx);
-            let opened_items = open_items(
-                serialized_workspace,
-                &workspace,
-                project_paths,
-                app_state,
-                cx,
-            )
-            .await
-            .unwrap_or_default();
+            notify_if_database_failed(window, &mut cx);
+            let opened_items = window
+                .update(&mut cx, |_workspace, cx| {
+                    let workspace = cx.view().downgrade();
+                    open_items(
+                        serialized_workspace,
+                        &workspace,
+                        project_paths,
+                        app_state,
+                        cx,
+                    )
+                })
+                .await
+                .unwrap_or_default();
 
-            (workspace, opened_items)
+            (window, opened_items)
         })
     }
 
@@ -2945,7 +2948,7 @@ impl Workspace {
     ) -> Result<()> {
         let this = this.upgrade().context("workspace dropped")?;
 
-        let item_builders = cx.update(|cx| {
+        let item_builders = cx.update(|_, cx| {
             cx.default_global::<FollowableItemBuilders>()
                 .values()
                 .map(|b| b.0)
@@ -2964,7 +2967,7 @@ impl Workspace {
                     Err(anyhow!("missing view variant"))?;
                 }
                 for build_item in &item_builders {
-                    let task = cx.update(|cx| {
+                    let task = cx.update(|_, cx| {
                         build_item(pane.clone(), this.clone(), id, &mut variant, cx)
                     })?;
                     if let Some(task) = task {
@@ -3364,12 +3367,11 @@ impl Workspace {
     }
 
     pub(crate) fn load_workspace(
-        workspace: WeakView<Workspace>,
         serialized_workspace: SerializedWorkspace,
         paths_to_open: Vec<Option<ProjectPath>>,
-        cx: &mut WindowContext,
+        cx: &mut ViewContext<Workspace>,
     ) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
-        cx.spawn(|_, mut cx| async move {
+        cx.spawn(|workspace, mut cx| async move {
             let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| {
                 (
                     workspace.project().clone(),
@@ -3382,7 +3384,7 @@ impl Workspace {
             // Traverse the splits tree and add to things
             if let Some((group, active_pane, items)) = serialized_workspace
                 .center_group
-                .deserialize(&project, serialized_workspace.id, &workspace, &mut cx)
+                .deserialize(&project, serialized_workspace.id, workspace, &mut cx)
                 .await
             {
                 center_items = Some(items);
@@ -3558,36 +3560,28 @@ fn window_bounds_env_override(cx: &MainThread<AsyncAppContext>) -> Option<Window
 
 async fn open_items(
     serialized_workspace: Option<SerializedWorkspace>,
-    workspace: &WeakView<Workspace>,
     mut project_paths_to_open: Vec<(PathBuf, Option<ProjectPath>)>,
     app_state: Arc<AppState>,
-    mut cx: MainThread<AsyncAppContext>,
+    mut cx: &mut MainThread<ViewContext<'_, Workspace>>,
 ) -> Result<Vec<Option<Result<Box<dyn ItemHandle>>>>> {
     let mut opened_items = Vec::with_capacity(project_paths_to_open.len());
 
     if let Some(serialized_workspace) = serialized_workspace {
-        let workspace = workspace.clone();
-        let restored_items = cx
-            .update(|cx| {
-                Workspace::load_workspace(
-                    workspace,
-                    serialized_workspace,
-                    project_paths_to_open
-                        .iter()
-                        .map(|(_, project_path)| project_path)
-                        .cloned()
-                        .collect(),
-                    cx,
-                )
-            })?
-            .await?;
-
-        let restored_project_paths = cx.update(|cx| {
-            restored_items
+        let restored_items = Workspace::load_workspace(
+            serialized_workspace,
+            project_paths_to_open
                 .iter()
-                .filter_map(|item| item.as_ref()?.project_path(cx))
-                .collect::<HashSet<_>>()
-        })?;
+                .map(|(_, project_path)| project_path)
+                .cloned()
+                .collect(),
+            cx,
+        )
+        .await?;
+
+        let restored_project_paths = restored_items
+            .iter()
+            .filter_map(|item| item.as_ref()?.project_path(cx))
+            .collect::<HashSet<_>>();
 
         for restored_item in restored_items {
             opened_items.push(restored_item.map(Ok));
@@ -3614,8 +3608,7 @@ async fn open_items(
             .into_iter()
             .enumerate()
             .map(|(i, (abs_path, project_path))| {
-                let workspace = workspace.clone();
-                cx.spawn(|mut cx| {
+                cx.spawn(|workspace, mut cx| {
                     let fs = app_state.fs.clone();
                     async move {
                         let file_project_path = project_path?;
@@ -3728,7 +3721,7 @@ async fn open_items(
 //         })
 //         .ok();
 
-fn notify_if_database_failed(_workspace: &WeakView<Workspace>, _cx: &mut AsyncAppContext) {
+fn notify_if_database_failed(_workspace: WindowHandle<Workspace>, _cx: &mut AsyncAppContext) {
     const REPORT_ISSUE_URL: &str ="https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml";
 
     // todo!()