WIP

Mikayla created

Change summary

crates/workspace2/src/item.rs              | 159 ++++----
crates/workspace2/src/persistence/model.rs | 261 +++++++-------
crates/workspace2/src/workspace2.rs        | 426 ++++++++++++-----------
crates/zed2/src/main.rs                    |  49 +-
crates/zed2/src/zed2.rs                    |   4 
5 files changed, 465 insertions(+), 434 deletions(-)

Detailed changes

crates/workspace2/src/item.rs 🔗

@@ -13,7 +13,7 @@ use client2::{
 };
 use gpui2::{
     AnyElement, AnyView, AppContext, EventEmitter, HighlightStyle, Model, Pixels, Point, Render,
-    SharedString, Task, View, ViewContext, WeakView, WindowContext,
+    SharedString, Task, View, ViewContext, WeakView, WindowContext, WindowHandle,
 };
 use parking_lot::Mutex;
 use project2::{Project, ProjectEntryId, ProjectPath};
@@ -190,7 +190,7 @@ pub trait Item: Render + EventEmitter + Send {
 
     fn deserialize(
         _project: Model<Project>,
-        _workspace: WeakView<Workspace>,
+        _workspace: WindowHandle<Workspace>,
         _workspace_id: WorkspaceId,
         _item_id: ItemId,
         _cx: &mut ViewContext<Pane>,
@@ -401,87 +401,86 @@ impl<T: Item> ItemHandle for View<T> {
             let pending_update = Arc::new(Mutex::new(None));
             let pending_update_scheduled = Arc::new(AtomicBool::new(false));
 
-            let mut event_subscription =
-                Some(cx.subscribe(self, move |workspace, item, event, cx| {
-                    let pane = if let Some(pane) = workspace
-                        .panes_by_item
-                        .get(&item.id())
-                        .and_then(|pane| pane.upgrade())
+            let event_subscription = Some(cx.subscribe(self, move |workspace, item, event, cx| {
+                let pane = if let Some(pane) = workspace
+                    .panes_by_item
+                    .get(&item.id())
+                    .and_then(|pane| pane.upgrade())
+                {
+                    pane
+                } else {
+                    log::error!("unexpected item event after pane was dropped");
+                    return;
+                };
+
+                if let Some(item) = item.to_followable_item_handle(cx) {
+                    let _is_project_item = item.is_project_item(cx);
+                    let leader_id = workspace.leader_for_pane(&pane);
+
+                    if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
+                        workspace.unfollow(&pane, cx);
+                    }
+
+                    if item.add_event_to_update_proto(event, &mut *pending_update.lock(), cx)
+                        && !pending_update_scheduled.load(Ordering::SeqCst)
                     {
-                        pane
-                    } else {
-                        log::error!("unexpected item event after pane was dropped");
-                        return;
-                    };
-
-                    if let Some(item) = item.to_followable_item_handle(cx) {
-                        let _is_project_item = item.is_project_item(cx);
-                        let leader_id = workspace.leader_for_pane(&pane);
-
-                        if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
-                            workspace.unfollow(&pane, cx);
+                        pending_update_scheduled.store(true, Ordering::SeqCst);
+                        todo!("replace with on_next_frame?");
+                        // cx.after_window_update({
+                        //     let pending_update = pending_update.clone();
+                        //     let pending_update_scheduled = pending_update_scheduled.clone();
+                        //     move |this, cx| {
+                        //         pending_update_scheduled.store(false, Ordering::SeqCst);
+                        //         this.update_followers(
+                        //             is_project_item,
+                        //             proto::update_followers::Variant::UpdateView(
+                        //                 proto::UpdateView {
+                        //                     id: item
+                        //                         .remote_id(&this.app_state.client, cx)
+                        //                         .map(|id| id.to_proto()),
+                        //                     variant: pending_update.borrow_mut().take(),
+                        //                     leader_id,
+                        //                 },
+                        //             ),
+                        //             cx,
+                        //         );
+                        //     }
+                        // });
+                    }
+                }
+
+                for item_event in T::to_item_events(event).into_iter() {
+                    match item_event {
+                        ItemEvent::CloseItem => {
+                            pane.update(cx, |pane, cx| {
+                                pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx)
+                            })
+                            .detach_and_log_err(cx);
+                            return;
                         }
 
-                        if item.add_event_to_update_proto(event, &mut *pending_update.lock(), cx)
-                            && !pending_update_scheduled.load(Ordering::SeqCst)
-                        {
-                            pending_update_scheduled.store(true, Ordering::SeqCst);
-                            todo!("replace with on_next_frame?");
-                            // cx.after_window_update({
-                            //     let pending_update = pending_update.clone();
-                            //     let pending_update_scheduled = pending_update_scheduled.clone();
-                            //     move |this, cx| {
-                            //         pending_update_scheduled.store(false, Ordering::SeqCst);
-                            //         this.update_followers(
-                            //             is_project_item,
-                            //             proto::update_followers::Variant::UpdateView(
-                            //                 proto::UpdateView {
-                            //                     id: item
-                            //                         .remote_id(&this.app_state.client, cx)
-                            //                         .map(|id| id.to_proto()),
-                            //                     variant: pending_update.borrow_mut().take(),
-                            //                     leader_id,
-                            //                 },
-                            //             ),
-                            //             cx,
-                            //         );
-                            //     }
-                            // });
+                        ItemEvent::UpdateTab => {
+                            pane.update(cx, |_, cx| {
+                                cx.emit(pane::Event::ChangeItemTitle);
+                                cx.notify();
+                            });
                         }
-                    }
 
-                    for item_event in T::to_item_events(event).into_iter() {
-                        match item_event {
-                            ItemEvent::CloseItem => {
-                                pane.update(cx, |pane, cx| {
-                                    pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx)
-                                })
-                                .detach_and_log_err(cx);
-                                return;
-                            }
-
-                            ItemEvent::UpdateTab => {
-                                pane.update(cx, |_, cx| {
-                                    cx.emit(pane::Event::ChangeItemTitle);
-                                    cx.notify();
+                        ItemEvent::Edit => {
+                            let autosave = WorkspaceSettings::get_global(cx).autosave;
+                            if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
+                                let delay = Duration::from_millis(milliseconds);
+                                let item = item.clone();
+                                pending_autosave.fire_new(delay, cx, move |workspace, cx| {
+                                    Pane::autosave_item(&item, workspace.project().clone(), cx)
                                 });
                             }
-
-                            ItemEvent::Edit => {
-                                let autosave = WorkspaceSettings::get_global(cx).autosave;
-                                if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
-                                    let delay = Duration::from_millis(milliseconds);
-                                    let item = item.clone();
-                                    pending_autosave.fire_new(delay, cx, move |workspace, cx| {
-                                        Pane::autosave_item(&item, workspace.project().clone(), cx)
-                                    });
-                                }
-                            }
-
-                            _ => {}
                         }
+
+                        _ => {}
                     }
-                }));
+                }
+            }));
 
             todo!("observe focus");
             // cx.observe_focus(self, move |workspace, item, focused, cx| {
@@ -494,12 +493,12 @@ impl<T: Item> ItemHandle for View<T> {
             // })
             // .detach();
 
-            let item_id = self.id();
-            cx.observe_release(self, move |workspace, _, _| {
-                workspace.panes_by_item.remove(&item_id);
-                event_subscription.take();
-            })
-            .detach();
+            // let item_id = self.id();
+            // cx.observe_release(self, move |workspace, _, _| {
+            //     workspace.panes_by_item.remove(&item_id);
+            //     event_subscription.take();
+            // })
+            // .detach();
         }
 
         cx.defer(|workspace, cx| {

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

@@ -1,21 +1,14 @@
-use crate::{
-    item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
-};
+use crate::{Axis, WorkspaceId};
 use anyhow::{Context, Result};
-use async_recursion::async_recursion;
 use db2::sqlez::{
     bindable::{Bind, Column, StaticColumnCount},
     statement::Statement,
 };
-use gpui2::{
-    AsyncAppContext, AsyncWindowContext, Model, Task, View, WeakView, WindowBounds, WindowHandle,
-};
-use project2::Project;
+use gpui2::WindowBounds;
 use std::{
     path::{Path, PathBuf},
     sync::Arc,
 };
-use util::ResultExt;
 use uuid::Uuid;
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -149,73 +142,75 @@ impl Default for SerializedPaneGroup {
     }
 }
 
-impl SerializedPaneGroup {
-    #[async_recursion(?Send)]
-    pub(crate) async fn deserialize(
-        self,
-        project: &Model<Project>,
-        workspace_id: WorkspaceId,
-        workspace: WindowHandle<Workspace>,
-        cx: &mut AsyncAppContext,
-    ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
-        match self {
-            SerializedPaneGroup::Group {
-                axis,
-                children,
-                flexes,
-            } => {
-                let mut current_active_pane = None;
-                let mut members = Vec::new();
-                let mut items = Vec::new();
-                for child in children {
-                    if let Some((new_member, active_pane, new_items)) = child
-                        .deserialize(project, workspace_id, workspace, cx)
-                        .await
-                    {
-                        members.push(new_member);
-                        items.extend(new_items);
-                        current_active_pane = current_active_pane.or(active_pane);
-                    }
-                }
-
-                if members.is_empty() {
-                    return None;
-                }
-
-                if members.len() == 1 {
-                    return Some((members.remove(0), current_active_pane, items));
-                }
-
-                Some((
-                    Member::Axis(PaneAxis::load(axis, members, flexes)),
-                    current_active_pane,
-                    items,
-                ))
-            }
-            SerializedPaneGroup::Pane(serialized_pane) => {
-                let pane = workspace
-                    .update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
-                    .log_err()?;
-                let active = serialized_pane.active;
-                let new_items = serialized_pane
-                    .deserialize_to(project, &pane, workspace_id, workspace, cx)
-                    .await
-                    .log_err()?;
-
-                if pane.update(cx, |pane, _| pane.items_len() != 0).log_err()? {
-                    let pane = pane.upgrade()?;
-                    Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
-                } else {
-                    let pane = pane.upgrade()?;
-                    workspace
-                        .update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
-                        .log_err()?;
-                    None
-                }
-            }
-        }
-    }
-}
+// impl SerializedPaneGroup {
+//     #[async_recursion(?Send)]
+//     pub(crate) async fn deserialize(
+//         self,
+//         project: &Model<Project>,
+//         workspace_id: WorkspaceId,
+//         workspace: WeakView<Workspace>,
+//         cx: &mut AsyncAppContext,
+//     ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
+//         match self {
+//             SerializedPaneGroup::Group {
+//                 axis,
+//                 children,
+//                 flexes,
+//             } => {
+//                 let mut current_active_pane = None;
+//                 let mut members = Vec::new();
+//                 let mut items = Vec::new();
+//                 for child in children {
+//                     if let Some((new_member, active_pane, new_items)) = child
+//                         .deserialize(project, workspace_id, workspace, cx)
+//                         .await
+//                     {
+//                         members.push(new_member);
+//                         items.extend(new_items);
+//                         current_active_pane = current_active_pane.or(active_pane);
+//                     }
+//                 }
+
+//                 if members.is_empty() {
+//                     return None;
+//                 }
+
+//                 if members.len() == 1 {
+//                     return Some((members.remove(0), current_active_pane, items));
+//                 }
+
+//                 Some((
+//                     Member::Axis(PaneAxis::load(axis, members, flexes)),
+//                     current_active_pane,
+//                     items,
+//                 ))
+//             }
+//             SerializedPaneGroup::Pane(serialized_pane) => {
+//                 let pane = workspace
+//                     .update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
+//                     .log_err()?;
+//                 let active = serialized_pane.active;
+//                 let new_items = serialized_pane
+//                     .deserialize_to(project, &pane, workspace_id, workspace, cx)
+//                     .await
+//                     .log_err()?;
+
+//                 // todo!();
+//                 // if pane.update(cx, |pane, _| pane.items_len() != 0).log_err()? {
+//                 //     let pane = pane.upgrade()?;
+//                 //     Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
+//                 // } else {
+//                 //     let pane = pane.upgrade()?;
+//                 //     workspace
+//                 //         .update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
+//                 //         .log_err()?;
+//                 //     None
+//                 // }
+//                 None
+//             }
+//         }
+//     }
+// }
 
 #[derive(Debug, PartialEq, Eq, Default, Clone)]
 pub struct SerializedPane {
@@ -228,53 +223,55 @@ impl SerializedPane {
         SerializedPane { children, active }
     }
 
-    pub async fn deserialize_to(
-        &self,
-        project: &Model<Project>,
-        pane: &WeakView<Pane>,
-        workspace_id: WorkspaceId,
-        workspace: WindowHandle<Workspace>,
-        cx: &mut AsyncAppContext,
-    ) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
-        let mut items = Vec::new();
-        let mut active_item_index = None;
-        for (index, item) in self.children.iter().enumerate() {
-            let project = project.clone();
-            let item_handle = pane
-                .update(cx, |_, cx| {
-                    if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
-                        deserializer(project, workspace, workspace_id, item.item_id, cx)
-                    } else {
-                        Task::ready(Err(anyhow::anyhow!(
-                            "Deserializer does not exist for item kind: {}",
-                            item.kind
-                        )))
-                    }
-                })?
-                .await
-                .log_err();
-
-            items.push(item_handle.clone());
-
-            if let Some(item_handle) = item_handle {
-                pane.update(cx, |pane, cx| {
-                    pane.add_item(item_handle.clone(), true, true, None, cx);
-                })?;
-            }
-
-            if item.active {
-                active_item_index = Some(index);
-            }
-        }
-
-        if let Some(active_item_index) = active_item_index {
-            pane.update(cx, |pane, cx| {
-                pane.activate_item(active_item_index, false, false, cx);
-            })?;
-        }
-
-        anyhow::Ok(items)
-    }
+    //     pub async fn deserialize_to(
+    //         &self,
+    //         _project: &Model<Project>,
+    //         _pane: &WeakView<Pane>,
+    //         _workspace_id: WorkspaceId,
+    //         _workspace: WindowHandle<Workspace>,
+    //         _cx: &mut AsyncAppContext,
+    //     ) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
+    //         anyhow::bail!("todo!()")
+    //         // todo!()
+    //         // let mut items = Vec::new();
+    //         // let mut active_item_index = None;
+    //         // for (index, item) in self.children.iter().enumerate() {
+    //         //     let project = project.clone();
+    //         //     let item_handle = pane
+    //         //         .update(cx, |_, cx| {
+    //         //             if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
+    //         //                 deserializer(project, workspace, workspace_id, item.item_id, cx)
+    //         //             } else {
+    //         //                 Task::ready(Err(anyhow::anyhow!(
+    //         //                     "Deserializer does not exist for item kind: {}",
+    //         //                     item.kind
+    //         //                 )))
+    //         //             }
+    //         //         })?
+    //         //         .await
+    //         //         .log_err();
+
+    //         //     items.push(item_handle.clone());
+
+    //         //     if let Some(item_handle) = item_handle {
+    //         //         pane.update(cx, |pane, cx| {
+    //         //             pane.add_item(item_handle.clone(), true, true, None, cx);
+    //         //         })?;
+    //         //     }
+
+    //         //     if item.active {
+    //         //         active_item_index = Some(index);
+    //         //     }
+    //         // }
+
+    //         // if let Some(active_item_index) = active_item_index {
+    //         //     pane.update(cx, |pane, cx| {
+    //         //         pane.activate_item(active_item_index, false, false, cx);
+    //         //     })?;
+    //         // }
+
+    //         // anyhow::Ok(items)
+    //     }
 }
 
 pub type GroupId = i64;
@@ -288,15 +285,15 @@ pub struct SerializedItem {
     pub active: bool,
 }
 
-impl SerializedItem {
-    pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
-        Self {
-            kind: Arc::from(kind.as_ref()),
-            item_id,
-            active,
-        }
-    }
-}
+// impl SerializedItem {
+//     pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
+//         Self {
+//             kind: Arc::from(kind.as_ref()),
+//             item_id,
+//             active,
+//         }
+//     }
+// }
 
 #[cfg(test)]
 impl Default for SerializedItem {

crates/workspace2/src/workspace2.rs 🔗

@@ -25,16 +25,16 @@ use dock::{Dock, DockPosition, PanelButtons};
 use futures::{
     channel::{mpsc, oneshot},
     future::try_join_all,
-    FutureExt, StreamExt,
+    Future, FutureExt, StreamExt,
 };
 use gpui2::{
     div, point, size, AnyModel, AnyView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds,
-    Context, Div, Entity, EventEmitter, GlobalPixels, MainThread, Model, ModelContext, Point,
-    Render, Size, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
-    WindowContext, WindowHandle, WindowOptions,
+    Context, Div, 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;
+use language2::{LanguageRegistry, LocalFile};
 use lazy_static::lazy_static;
 use node_runtime::NodeRuntime;
 use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
@@ -412,7 +412,7 @@ pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
                 Arc::from(serialized_item_kind),
                 |project, workspace, workspace_id, item_id, cx| {
                     let task = I::deserialize(project, workspace, workspace_id, item_id, cx);
-                    cx.spawn_on_main(|cx| async { Ok(Box::new(task.await?) as Box<_>) })
+                    cx.spawn_on_main(|_| async { Ok(Box::new(task.await?) as Box<_>) })
                 },
             );
         }
@@ -428,10 +428,10 @@ pub struct AppState {
     pub build_window_options:
         fn(Option<WindowBounds>, Option<Uuid>, &mut MainThread<AppContext>) -> WindowOptions,
     pub initialize_workspace: fn(
-        WindowHandle<Workspace>,
+        WeakView<Workspace>,
         bool,
         Arc<AppState>,
-        AsyncAppContext,
+        AsyncWindowContext,
     ) -> Task<anyhow::Result<()>>,
     pub node_runtime: Arc<dyn NodeRuntime>,
 }
@@ -568,6 +568,9 @@ pub struct Workspace {
     pane_history_timestamp: Arc<AtomicUsize>,
 }
 
+trait AssertSend: Send {}
+impl AssertSend for WindowHandle<Workspace> {}
+
 // struct ActiveModal {
 //     view: Box<dyn ModalHandle>,
 //     previously_focused_view_id: Option<usize>,
@@ -700,7 +703,7 @@ impl Workspace {
             cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), weak_handle.clone(), cx));
         let right_dock_buttons =
             cx.build_view(|cx| PanelButtons::new(right_dock.clone(), weak_handle.clone(), cx));
-        let status_bar = cx.build_view(|cx| {
+        let _status_bar = cx.build_view(|cx| {
             let mut status_bar = StatusBar::new(&center_pane.clone(), cx);
             status_bar.add_left_item(left_dock_buttons, cx);
             status_bar.add_right_item(right_dock_buttons, cx);
@@ -791,12 +794,14 @@ impl Workspace {
     fn new_local(
         abs_paths: Vec<PathBuf>,
         app_state: Arc<AppState>,
-        requesting_window: Option<WindowHandle<Workspace>>,
+        _requesting_window: Option<WindowHandle<Workspace>>,
         cx: &mut MainThread<AppContext>,
-    ) -> Task<(
-        WeakView<Workspace>,
-        Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
-    )> {
+    ) -> Task<
+        anyhow::Result<(
+            WindowHandle<Workspace>,
+            Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
+        )>,
+    > {
         let project_handle = Project::local(
             app_state.client.clone(),
             app_state.node_runtime.clone(),
@@ -807,7 +812,7 @@ impl Workspace {
         );
 
         cx.spawn_on_main(|mut cx| async move {
-            let serialized_workspace = persistence::DB.workspace_for_roots(&abs_paths.as_slice());
+            let serialized_workspace: Option<SerializedWorkspace> = None; //persistence::DB.workspace_for_roots(&abs_paths.as_slice());
 
             let paths_to_open = Arc::new(abs_paths);
 
@@ -836,14 +841,15 @@ impl Workspace {
                 DB.next_id().await.unwrap_or(0)
             };
 
-            let window = if let Some(window) = requesting_window {
+            // todo!()
+            let window = /*if let Some(window) = requesting_window {
                 cx.update_window(window.into(), |old_workspace, cx| {
                     cx.replace_root_view(|cx| {
                         Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
                     });
                 });
                 window
-            } else {
+                } else */ {
                 let window_bounds_override = window_bounds_env_override(&cx);
                 let (bounds, display) = if let Some(bounds) = window_bounds_override {
                     (Some(bounds), None)
@@ -873,23 +879,34 @@ impl Workspace {
                 // Use the serialized workspace to construct the new window
                 let options =
                     cx.update(|cx| (app_state.build_window_options)(bounds, display, cx))?;
-                cx.open_window(options, |cx| {
+
+                cx.open_window(options, {
+                    let app_state = app_state.clone();
+                    let workspace_id = workspace_id.clone();
+                    let project_handle = project_handle.clone();
+                    move |cx| {
                     cx.build_view(|cx| {
-                        Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
+                        Workspace::new(workspace_id, project_handle, app_state, cx)
                     })
-                })?
-            };
+                }})?
+                 };
+
+            // todo!() Ask how to do this
+            let weak_view = window.update(&mut cx, |_, cx| cx.view().downgrade())?;
+            let async_cx = window.update(&mut cx, |_, cx| cx.to_async())?;
 
             (app_state.initialize_workspace)(
-                window,
+                weak_view,
                 serialized_workspace.is_some(),
                 app_state.clone(),
-                cx.clone(),
+                async_cx,
             )
             .await
             .log_err();
 
-            window.update(&mut cx, |_, cx| cx.activate_window());
+            window
+                .update(&mut cx, |_, cx| cx.activate_window())
+                .log_err();
 
             notify_if_database_failed(window, &mut cx);
             let opened_items = window
@@ -897,16 +914,16 @@ impl Workspace {
                     let workspace = cx.view().downgrade();
                     open_items(
                         serialized_workspace,
-                        &workspace,
+                        //    &workspace,
                         project_paths,
                         app_state,
                         cx,
                     )
-                })
+                })?
                 .await
                 .unwrap_or_default();
 
-            (window, opened_items)
+            Ok((window, opened_items))
         })
     }
 
@@ -2102,9 +2119,9 @@ impl Workspace {
     > {
         let project = self.project().clone();
         let project_item = project.update(cx, |project, cx| project.open_path(path, cx));
-        cx.spawn(|_, cx| async move {
+        cx.spawn(|_, mut cx| async move {
             let (project_entry_id, project_item) = project_item.await?;
-            let build_item = cx.update(|cx| {
+            let build_item = cx.update(|_, cx| {
                 cx.default_global::<ProjectItemBuilders>()
                     .get(&project_item.type_id())
                     .ok_or_else(|| anyhow!("no item builder for project item"))
@@ -2747,7 +2764,7 @@ impl Workspace {
             title.push_str(" ↗");
         }
 
-        todo!()
+        // todo!()
         // cx.set_window_title(&title);
     }
 
@@ -3372,122 +3389,126 @@ impl Workspace {
         cx: &mut ViewContext<Workspace>,
     ) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
         cx.spawn(|workspace, mut cx| async move {
-            let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| {
-                (
-                    workspace.project().clone(),
-                    workspace.last_active_center_pane.clone(),
-                )
-            })?;
-
-            let mut center_group = None;
-            let mut center_items = None;
-            // 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)
-                .await
-            {
-                center_items = Some(items);
-                center_group = Some((group, active_pane))
-            }
+            // let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| {
+            //     (
+            //         workspace.project().clone(),
+            //         workspace.last_active_center_pane.clone(),
+            //     )
+            // })?;
+
+            // // let mut center_group: Option = None;
+            // // let mut center_items: Option<Vec<Option<Box<dyn ItemHandle>>>> = None;
+
+            // // todo!()
+            // // // 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)
+            //     .await
+            // {
+            //     center_items = Some(items);
+            //     center_group = Some((group, active_pane))
+            // }
 
-            let mut items_by_project_path = cx.update(|cx| {
-                center_items
-                    .unwrap_or_default()
-                    .into_iter()
-                    .filter_map(|item| {
-                        let item = item?;
-                        let project_path = item.project_path(cx)?;
-                        Some((project_path, item))
-                    })
-                    .collect::<HashMap<_, _>>()
-            })?;
-
-            let opened_items = paths_to_open
-                .into_iter()
-                .map(|path_to_open| {
-                    path_to_open
-                        .and_then(|path_to_open| items_by_project_path.remove(&path_to_open))
-                })
-                .collect::<Vec<_>>();
+            // let mut items_by_project_path = cx.update(|_, cx| {
+            //     center_items
+            //         .unwrap_or_default()
+            //         .into_iter()
+            //         .filter_map(|item| {
+            //             let item = item?;
+            //             let project_path = item.project_path(cx)?;
+            //             Some((project_path, item))
+            //         })
+            //         .collect::<HashMap<_, _>>()
+            // })?;
+
+            // let opened_items = paths_to_open
+            //     .into_iter()
+            //     .map(|path_to_open| {
+            //         path_to_open
+            //             .and_then(|path_to_open| items_by_project_path.remove(&path_to_open))
+            //     })
+            //     .collect::<Vec<_>>();
 
-            // Remove old panes from workspace panes list
-            workspace.update(&mut cx, |workspace, cx| {
-                if let Some((center_group, active_pane)) = center_group {
-                    workspace.remove_panes(workspace.center.root.clone(), cx);
+            // todo!()
+            // // Remove old panes from workspace panes list
+            // workspace.update(&mut cx, |workspace, cx| {
+            //     if let Some((center_group, active_pane)) = center_group {
+            //         workspace.remove_panes(workspace.center.root.clone(), cx);
 
-                    // Swap workspace center group
-                    workspace.center = PaneGroup::with_root(center_group);
+            //         // Swap workspace center group
+            //         workspace.center = PaneGroup::with_root(center_group);
 
-                    // Change the focus to the workspace first so that we retrigger focus in on the pane.
-                    cx.focus_self();
+            //         // Change the focus to the workspace first so that we retrigger focus in on the pane.
+            //         cx.focus_self();
 
-                    if let Some(active_pane) = active_pane {
-                        cx.focus(&active_pane);
-                    } else {
-                        cx.focus(workspace.panes.last().unwrap());
-                    }
-                } else {
-                    let old_center_handle = old_center_pane.and_then(|weak| weak.upgrade());
-                    if let Some(old_center_handle) = old_center_handle {
-                        cx.focus(&old_center_handle)
-                    } else {
-                        cx.focus_self()
-                    }
-                }
+            //         if let Some(active_pane) = active_pane {
+            //             cx.focus(&active_pane);
+            //         } else {
+            //             cx.focus(workspace.panes.last().unwrap());
+            //         }
+            //     } else {
+            //         let old_center_handle = old_center_pane.and_then(|weak| weak.upgrade());
+            //         if let Some(old_center_handle) = old_center_handle {
+            //             cx.focus(&old_center_handle)
+            //         } else {
+            //             cx.focus_self()
+            //         }
+            //     }
 
-                let docks = serialized_workspace.docks;
-                workspace.left_dock.update(cx, |dock, cx| {
-                    dock.set_open(docks.left.visible, cx);
-                    if let Some(active_panel) = docks.left.active_panel {
-                        if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
-                            dock.activate_panel(ix, cx);
-                        }
-                    }
-                    dock.active_panel()
-                        .map(|panel| panel.set_zoomed(docks.left.zoom, cx));
-                    if docks.left.visible && docks.left.zoom {
-                        cx.focus_self()
-                    }
-                });
-                // TODO: I think the bug is that setting zoom or active undoes the bottom zoom or something
-                workspace.right_dock.update(cx, |dock, cx| {
-                    dock.set_open(docks.right.visible, cx);
-                    if let Some(active_panel) = docks.right.active_panel {
-                        if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
-                            dock.activate_panel(ix, cx);
-                        }
-                    }
-                    dock.active_panel()
-                        .map(|panel| panel.set_zoomed(docks.right.zoom, cx));
+            //     let docks = serialized_workspace.docks;
+            //     workspace.left_dock.update(cx, |dock, cx| {
+            //         dock.set_open(docks.left.visible, cx);
+            //         if let Some(active_panel) = docks.left.active_panel {
+            //             if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
+            //                 dock.activate_panel(ix, cx);
+            //             }
+            //         }
+            //         dock.active_panel()
+            //             .map(|panel| panel.set_zoomed(docks.left.zoom, cx));
+            //         if docks.left.visible && docks.left.zoom {
+            //             cx.focus_self()
+            //         }
+            //     });
+            //     // TODO: I think the bug is that setting zoom or active undoes the bottom zoom or something
+            //     workspace.right_dock.update(cx, |dock, cx| {
+            //         dock.set_open(docks.right.visible, cx);
+            //         if let Some(active_panel) = docks.right.active_panel {
+            //             if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
+            //                 dock.activate_panel(ix, cx);
+            //             }
+            //         }
+            //         dock.active_panel()
+            //             .map(|panel| panel.set_zoomed(docks.right.zoom, cx));
 
-                    if docks.right.visible && docks.right.zoom {
-                        cx.focus_self()
-                    }
-                });
-                workspace.bottom_dock.update(cx, |dock, cx| {
-                    dock.set_open(docks.bottom.visible, cx);
-                    if let Some(active_panel) = docks.bottom.active_panel {
-                        if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
-                            dock.activate_panel(ix, cx);
-                        }
-                    }
+            //         if docks.right.visible && docks.right.zoom {
+            //             cx.focus_self()
+            //         }
+            //     });
+            //     workspace.bottom_dock.update(cx, |dock, cx| {
+            //         dock.set_open(docks.bottom.visible, cx);
+            //         if let Some(active_panel) = docks.bottom.active_panel {
+            //             if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
+            //                 dock.activate_panel(ix, cx);
+            //             }
+            //         }
 
-                    dock.active_panel()
-                        .map(|panel| panel.set_zoomed(docks.bottom.zoom, cx));
+            //         dock.active_panel()
+            //             .map(|panel| panel.set_zoomed(docks.bottom.zoom, cx));
 
-                    if docks.bottom.visible && docks.bottom.zoom {
-                        cx.focus_self()
-                    }
-                });
+            //         if docks.bottom.visible && docks.bottom.zoom {
+            //             cx.focus_self()
+            //         }
+            //     });
 
-                cx.notify();
-            })?;
+            //     cx.notify();
+            // })?;
 
             // Serialize ourself to make sure our timestamps and any pane / item changes are replicated
-            workspace.update(&mut cx, |workspace, cx| workspace.serialize_workspace(cx))?;
+            // workspace.update(&mut cx, |workspace, cx| workspace.serialize_workspace(cx))?;
 
-            Ok(opened_items)
+            // Ok(opened_items)
+            anyhow::bail!("todo")
         })
     }
 
@@ -3558,49 +3579,50 @@ fn window_bounds_env_override(cx: &MainThread<AsyncAppContext>) -> Option<Window
         })
 }
 
-async fn open_items(
-    serialized_workspace: Option<SerializedWorkspace>,
-    mut project_paths_to_open: Vec<(PathBuf, Option<ProjectPath>)>,
+fn open_items(
+    _serialized_workspace: Option<SerializedWorkspace>,
+    project_paths_to_open: Vec<(PathBuf, Option<ProjectPath>)>,
     app_state: Arc<AppState>,
-    mut cx: &mut MainThread<ViewContext<'_, Workspace>>,
-) -> Result<Vec<Option<Result<Box<dyn ItemHandle>>>>> {
+    cx: &mut MainThread<ViewContext<'_, Workspace>>,
+) -> impl Future<Output = 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 restored_items = Workspace::load_workspace(
-            serialized_workspace,
-            project_paths_to_open
-                .iter()
-                .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));
-        }
+    // todo!()
+    // if let Some(serialized_workspace) = serialized_workspace {
+    //     let restored_items = Workspace::load_workspace(
+    //         serialized_workspace,
+    //         project_paths_to_open
+    //             .iter()
+    //             .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));
+    //     }
 
-        project_paths_to_open
-            .iter_mut()
-            .for_each(|(_, project_path)| {
-                if let Some(project_path_to_open) = project_path {
-                    if restored_project_paths.contains(project_path_to_open) {
-                        *project_path = None;
-                    }
-                }
-            });
-    } else {
-        for _ in 0..project_paths_to_open.len() {
-            opened_items.push(None);
-        }
+    //     project_paths_to_open
+    //         .iter_mut()
+    //         .for_each(|(_, project_path)| {
+    //             if let Some(project_path_to_open) = project_path {
+    //                 if restored_project_paths.contains(project_path_to_open) {
+    //                     *project_path = None;
+    //                 }
+    //             }
+    //         });
+    // } else {
+    for _ in 0..project_paths_to_open.len() {
+        opened_items.push(None);
     }
+    // }
     assert!(opened_items.len() == project_paths_to_open.len());
 
     let tasks =
@@ -3629,16 +3651,17 @@ async fn open_items(
                 })
             });
 
-    for maybe_opened_path in futures::future::join_all(tasks.into_iter())
-        .await
-        .into_iter()
-    {
-        if let Some((i, path_open_result)) = maybe_opened_path {
-            opened_items[i] = Some(path_open_result);
+    let tasks = tasks.collect::<Vec<_>>();
+    async move {
+        let tasks = futures::future::join_all(tasks.into_iter());
+        for maybe_opened_path in tasks.await.into_iter() {
+            if let Some((i, path_open_result)) = maybe_opened_path {
+                opened_items[i] = Some(path_open_result);
+            }
         }
-    }
 
-    Ok(opened_items)
+        Ok(opened_items)
+    }
 }
 
 // fn notify_of_new_dock(workspace: &WeakView<Workspace>, cx: &mut AsyncAppContext) {
@@ -4102,8 +4125,8 @@ pub async fn activate_workspace_for_project(
                 continue;
             };
 
-            let predicate = cx
-                .update_window_root(&workspace, |workspace, cx| {
+            let predicate = workspace
+                .update(cx, |workspace, cx| {
                     let project = workspace.project.read(cx);
                     if predicate(project, cx) {
                         cx.activate_window();
@@ -4326,10 +4349,11 @@ pub fn open_paths(
 > {
     let app_state = app_state.clone();
     let abs_paths = abs_paths.to_vec();
-    cx.spawn(move |mut cx| async move {
+    cx.spawn_on_main(move |mut cx| async move {
         // Open paths in existing workspace if possible
-        let existing = activate_workspace_for_project(&mut cx, move |project, cx| {
-            project.contains_paths(&abs_paths, cx)
+        let existing = activate_workspace_for_project(&mut cx, {
+            let abs_paths = abs_paths.clone();
+            move |project, cx| project.contains_paths(&abs_paths, cx)
         })
         .await;
 
@@ -4343,32 +4367,30 @@ pub fn open_paths(
             // ))
             todo!()
         } else {
-            // Ok(cx
-            //     .update(|cx| {
-            //         Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx)
-            //     })
-            //     .await)
-            todo!()
+            cx.update(move |cx| {
+                Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx)
+            })?
+            .await
         }
     })
 }
 
 pub fn open_new(
     app_state: &Arc<AppState>,
-    cx: &mut AppContext,
-    init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static,
+    cx: &mut MainThread<AppContext>,
+    init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send,
 ) -> Task<()> {
     let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx);
-    cx.spawn(|mut cx| async move {
-        let (workspace, opened_paths) = task.await;
-
-        workspace
-            .update(&mut cx, |workspace, cx| {
-                if opened_paths.is_empty() {
-                    init(workspace, cx)
-                }
-            })
-            .log_err();
+    cx.spawn_on_main(|mut cx| async move {
+        if let Some((workspace, opened_paths)) = task.await.log_err() {
+            workspace
+                .update(&mut cx, |workspace, cx| {
+                    if opened_paths.is_empty() {
+                        init(workspace, cx)
+                    }
+                })
+                .log_err();
+        }
     })
 }
 

crates/zed2/src/main.rs 🔗

@@ -12,7 +12,7 @@ use client2::UserStore;
 use db2::kvp::KEY_VALUE_STORE;
 use fs2::RealFs;
 use futures::{channel::mpsc, SinkExt, StreamExt};
-use gpui2::{Action, App, AppContext, AsyncAppContext, Context, SemanticVersion, Task};
+use gpui2::{Action, App, AppContext, AsyncAppContext, Context, MainThread, SemanticVersion, Task};
 use isahc::{prelude::Configurable, Request};
 use language2::LanguageRegistry;
 use log::LevelFilter;
@@ -24,7 +24,7 @@ use settings2::{
     default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore,
 };
 use simplelog::ConfigBuilder;
-use smol::process::Command;
+use smol::{future::FutureExt, process::Command};
 use std::{
     env,
     ffi::OsStr,
@@ -40,6 +40,7 @@ use std::{
     time::{SystemTime, UNIX_EPOCH},
 };
 use util::{
+    async_maybe,
     channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
     http::{self, HttpClient},
     paths, ResultExt,
@@ -242,7 +243,7 @@ fn main() {
                 // .detach_and_log_err(cx)
             }
             Ok(None) | Err(_) => cx
-                .spawn({
+                .spawn_on_main({
                     let app_state = app_state.clone();
                     |cx| async move { restore_or_create_workspace(&app_state, cx).await }
                 })
@@ -313,21 +314,33 @@ async fn installation_id() -> Result<String> {
     }
 }
 
-async fn restore_or_create_workspace(app_state: &Arc<AppState>, mut cx: AsyncAppContext) {
-    if let Some(location) = workspace2::last_opened_workspace_paths().await {
-        cx.update(|cx| workspace2::open_paths(location.paths().as_ref(), app_state, None, cx))?
-            .await
-            .log_err();
-    } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
-        cx.update(|cx| show_welcome_experience(app_state, cx));
-    } else {
-        cx.update(|cx| {
-            workspace2::open_new(app_state, cx, |workspace, cx| {
-                Editor::new_file(workspace, &Default::default(), cx)
-            })
-            .detach();
-        });
-    }
+async fn restore_or_create_workspace(
+    app_state: &Arc<AppState>,
+    mut cx: MainThread<AsyncAppContext>,
+) {
+    async_maybe!({
+        if let Some(location) = workspace2::last_opened_workspace_paths().await {
+            cx.update(|cx| workspace2::open_paths(location.paths().as_ref(), app_state, None, cx))?
+                .await
+                .log_err();
+        } else if matches!(KEY_VALUE_STORE.read_kvp("******* THIS IS A BAD KEY PLEASE UNCOMMENT BELOW TO FIX THIS VERY LONG LINE *******"), Ok(None)) {
+            // todo!(welcome)
+            //} else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
+            //todo!()
+            // cx.update(|cx| show_welcome_experience(app_state, cx));
+        } else {
+            cx.update(|cx| {
+                workspace2::open_new(app_state, cx, |workspace, cx| {
+                    // todo!(editor)
+                    // Editor::new_file(workspace, &Default::default(), cx)
+                })
+                .detach();
+            })?;
+        }
+        anyhow::Ok(())
+    })
+    .await
+    .log_err();
 }
 
 fn init_paths() {

crates/zed2/src/zed2.rs 🔗

@@ -7,7 +7,7 @@ pub use assets::*;
 use collections::HashMap;
 use gpui2::{
     point, px, AppContext, AsyncAppContext, AsyncWindowContext, MainThread, Point, Task,
-    TitlebarOptions, WeakView, WindowBounds, WindowKind, WindowOptions,
+    TitlebarOptions, WeakView, WindowBounds, WindowHandle, WindowKind, WindowOptions,
 };
 pub use only_instance::*;
 pub use open_listener::*;
@@ -165,7 +165,7 @@ pub async fn handle_cli_connection(
                                     if paths.is_empty() {
                                         let (done_tx, done_rx) = oneshot::channel();
                                         let _subscription =
-                                            cx.update_window_root(&workspace, move |_, cx| {
+                                            workspace.update(&mut cx, move |_, cx| {
                                                 cx.on_release(|_, _| {
                                                     let _ = done_tx.send(());
                                                 })