Replace build_workspace fn with an initialize function that takes a workspace

Max Brunsfeld created

This makes it clearer that the function is not providing necessary
dependencies to a workspace, but rather configuring it with all of
the panels and widgets which are defined in downstream crates.

Change summary

crates/collab/src/rpc.rs                    |   2 
crates/contacts_panel/src/contacts_panel.rs |   4 
crates/workspace/src/waiting_room.rs        | 151 +++++++++++-----------
crates/workspace/src/workspace.rs           |  36 +++--
crates/zed/src/main.rs                      |   6 
crates/zed/src/zed.rs                       |  37 +++--
6 files changed, 123 insertions(+), 113 deletions(-)

Detailed changes

crates/collab/src/rpc.rs 🔗

@@ -6598,7 +6598,7 @@ mod tests {
                 themes: ThemeRegistry::new((), cx.font_cache()),
                 fs: FakeFs::new(cx.background()),
                 build_window_options: || Default::default(),
-                build_workspace: |_, _, _| unimplemented!(),
+                initialize_workspace: |_, _, _| unimplemented!(),
             });
 
             Channel::init(&client);

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -1111,8 +1111,8 @@ mod tests {
                 client,
                 user_store: user_store.clone(),
                 fs,
-                build_window_options: || unimplemented!(),
-                build_workspace: |_, _, _| unimplemented!(),
+                build_window_options: || Default::default(),
+                initialize_workspace: |_, _, _| {},
             }),
             server,
         )

crates/workspace/src/waiting_room.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{
     sidebar::{Side, ToggleSidebarItem},
-    AppState, ToggleFollow,
+    AppState, ToggleFollow, Workspace,
 };
 use anyhow::Result;
 use client::{proto, Client, Contact};
@@ -77,86 +77,87 @@ impl WaitingRoom {
     ) -> Self {
         let project_id = contact.projects[project_index].id;
         let client = app_state.client.clone();
-        let _join_task = cx.spawn_weak({
-            let contact = contact.clone();
-            |this, mut cx| async move {
-                let project = Project::remote(
-                    project_id,
-                    app_state.client.clone(),
-                    app_state.user_store.clone(),
-                    app_state.languages.clone(),
-                    app_state.fs.clone(),
-                    &mut cx,
-                )
-                .await;
+        let _join_task =
+            cx.spawn_weak({
+                let contact = contact.clone();
+                |this, mut cx| async move {
+                    let project = Project::remote(
+                        project_id,
+                        app_state.client.clone(),
+                        app_state.user_store.clone(),
+                        app_state.languages.clone(),
+                        app_state.fs.clone(),
+                        &mut cx,
+                    )
+                    .await;
 
-                if let Some(this) = this.upgrade(&cx) {
-                    this.update(&mut cx, |this, cx| {
-                        this.waiting = false;
-                        match project {
-                            Ok(project) => {
-                                cx.replace_root_view(|cx| {
-                                    let mut workspace = (app_state.build_workspace)(
-                                        project.clone(),
-                                        &app_state,
-                                        cx,
-                                    );
-                                    workspace.toggle_sidebar_item(
-                                        &ToggleSidebarItem {
-                                            side: Side::Left,
-                                            item_index: 0,
-                                        },
-                                        cx,
-                                    );
-                                    if let Some((host_peer_id, _)) = project
-                                        .read(cx)
-                                        .collaborators()
-                                        .iter()
-                                        .find(|(_, collaborator)| collaborator.replica_id == 0)
-                                    {
-                                        if let Some(follow) = workspace
-                                            .toggle_follow(&ToggleFollow(*host_peer_id), cx)
+                    if let Some(this) = this.upgrade(&cx) {
+                        this.update(&mut cx, |this, cx| {
+                            this.waiting = false;
+                            match project {
+                                Ok(project) => {
+                                    cx.replace_root_view(|cx| {
+                                        let mut workspace = Workspace::new(project, cx);
+                                        (app_state.initialize_workspace)(
+                                            &mut workspace,
+                                            &app_state,
+                                            cx,
+                                        );
+                                        workspace.toggle_sidebar_item(
+                                            &ToggleSidebarItem {
+                                                side: Side::Left,
+                                                item_index: 0,
+                                            },
+                                            cx,
+                                        );
+                                        if let Some((host_peer_id, _)) =
+                                            workspace.project.read(cx).collaborators().iter().find(
+                                                |(_, collaborator)| collaborator.replica_id == 0,
+                                            )
                                         {
-                                            follow.detach_and_log_err(cx);
+                                            if let Some(follow) = workspace
+                                                .toggle_follow(&ToggleFollow(*host_peer_id), cx)
+                                            {
+                                                follow.detach_and_log_err(cx);
+                                            }
                                         }
-                                    }
-                                    workspace
-                                });
-                            }
-                            Err(error @ _) => {
-                                let login = &contact.user.github_login;
-                                let message = match error {
-                                    project::JoinProjectError::HostDeclined => {
-                                        format!("@{} declined your request.", login)
-                                    }
-                                    project::JoinProjectError::HostClosedProject => {
-                                        format!(
-                                            "@{} closed their copy of {}.",
-                                            login,
-                                            humanize_list(
-                                                &contact.projects[project_index]
-                                                    .worktree_root_names
+                                        workspace
+                                    });
+                                }
+                                Err(error @ _) => {
+                                    let login = &contact.user.github_login;
+                                    let message = match error {
+                                        project::JoinProjectError::HostDeclined => {
+                                            format!("@{} declined your request.", login)
+                                        }
+                                        project::JoinProjectError::HostClosedProject => {
+                                            format!(
+                                                "@{} closed their copy of {}.",
+                                                login,
+                                                humanize_list(
+                                                    &contact.projects[project_index]
+                                                        .worktree_root_names
+                                                )
                                             )
-                                        )
-                                    }
-                                    project::JoinProjectError::HostWentOffline => {
-                                        format!("@{} went offline.", login)
-                                    }
-                                    project::JoinProjectError::Other(error) => {
-                                        log::error!("error joining project: {}", error);
-                                        "An error occurred.".to_string()
-                                    }
-                                };
-                                this.message = message;
-                                cx.notify();
+                                        }
+                                        project::JoinProjectError::HostWentOffline => {
+                                            format!("@{} went offline.", login)
+                                        }
+                                        project::JoinProjectError::Other(error) => {
+                                            log::error!("error joining project: {}", error);
+                                            "An error occurred.".to_string()
+                                        }
+                                    };
+                                    this.message = message;
+                                    cx.notify();
+                                }
                             }
-                        }
-                    })
-                }
+                        })
+                    }
 
-                Ok(())
-            }
-        });
+                    Ok(())
+                }
+            });
 
         Self {
             project_id,

crates/workspace/src/workspace.rs 🔗

@@ -190,8 +190,7 @@ pub struct AppState {
     pub user_store: ModelHandle<client::UserStore>,
     pub fs: Arc<dyn fs::Fs>,
     pub build_window_options: fn() -> WindowOptions<'static>,
-    pub build_workspace:
-        fn(ModelHandle<Project>, &Arc<AppState>, &mut ViewContext<Workspace>) -> Workspace,
+    pub initialize_workspace: fn(&mut Workspace, &Arc<AppState>, &mut ViewContext<Workspace>),
 }
 
 pub trait Item: View {
@@ -654,7 +653,7 @@ impl AppState {
             fs,
             languages,
             user_store,
-            build_workspace: |project, _, cx| Workspace::new(project, cx),
+            initialize_workspace: |_, _, _| {},
             build_window_options: || Default::default(),
         })
     }
@@ -2219,14 +2218,17 @@ pub fn open_paths(
                     .contains(&false);
 
             cx.add_window((app_state.build_window_options)(), |cx| {
-                let project = Project::local(
-                    app_state.client.clone(),
-                    app_state.user_store.clone(),
-                    app_state.languages.clone(),
-                    app_state.fs.clone(),
+                let mut workspace = Workspace::new(
+                    Project::local(
+                        app_state.client.clone(),
+                        app_state.user_store.clone(),
+                        app_state.languages.clone(),
+                        app_state.fs.clone(),
+                        cx,
+                    ),
                     cx,
                 );
-                let mut workspace = (app_state.build_workspace)(project, &app_state, cx);
+                (app_state.initialize_workspace)(&mut workspace, &app_state, cx);
                 if contains_directory {
                     workspace.toggle_sidebar_item(
                         &ToggleSidebarItem {
@@ -2272,14 +2274,18 @@ pub fn join_project(
 
 fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
     let (window_id, workspace) = cx.add_window((app_state.build_window_options)(), |cx| {
-        let project = Project::local(
-            app_state.client.clone(),
-            app_state.user_store.clone(),
-            app_state.languages.clone(),
-            app_state.fs.clone(),
+        let mut workspace = Workspace::new(
+            Project::local(
+                app_state.client.clone(),
+                app_state.user_store.clone(),
+                app_state.languages.clone(),
+                app_state.fs.clone(),
+                cx,
+            ),
             cx,
         );
-        (app_state.build_workspace)(project, app_state, cx)
+        (app_state.initialize_workspace)(&mut workspace, app_state, cx);
+        workspace
     });
     cx.dispatch_action(window_id, vec![workspace.id()], &OpenNew);
 }

crates/zed/src/main.rs 🔗

@@ -40,9 +40,9 @@ use theme::{ThemeRegistry, DEFAULT_THEME_NAME};
 use util::{ResultExt, TryFutureExt};
 use workspace::{self, AppState, OpenNew, OpenPaths};
 use zed::{
-    self, build_window_options, build_workspace,
+    self, build_window_options,
     fs::RealFs,
-    languages, menus,
+    initialize_workspace, languages, menus,
     settings_file::{settings_from_files, watch_keymap_file, WatchedJsonFile},
 };
 
@@ -193,7 +193,7 @@ fn main() {
             user_store,
             fs,
             build_window_options,
-            build_workspace,
+            initialize_workspace,
         });
         workspace::init(app_state.clone(), cx);
         journal::init(app_state.clone(), cx);

crates/zed/src/zed.rs 🔗

@@ -15,7 +15,7 @@ use gpui::{
     actions,
     geometry::vector::vec2f,
     platform::{WindowBounds, WindowOptions},
-    AsyncAppContext, ModelHandle, ViewContext,
+    AsyncAppContext, ViewContext,
 };
 use lazy_static::lazy_static;
 pub use lsp;
@@ -115,13 +115,13 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
     settings::KeymapFileContent::load_defaults(cx);
 }
 
-pub fn build_workspace(
-    project: ModelHandle<Project>,
+pub fn initialize_workspace(
+    workspace: &mut Workspace,
     app_state: &Arc<AppState>,
     cx: &mut ViewContext<Workspace>,
-) -> Workspace {
+) {
     cx.subscribe(&cx.handle(), {
-        let project = project.clone();
+        let project = workspace.project().clone();
         move |_, _, event, cx| {
             if let workspace::Event::PaneAdded(pane) = event {
                 pane.update(cx, |pane, cx| {
@@ -139,11 +139,12 @@ pub fn build_workspace(
     })
     .detach();
 
-    let workspace = Workspace::new(project.clone(), cx);
+    cx.emit(workspace::Event::PaneAdded(workspace.active_pane().clone()));
+
     let theme_names = app_state.themes.list().collect();
     let language_names = app_state.languages.language_names();
 
-    project.update(cx, |project, cx| {
+    workspace.project().update(cx, |project, cx| {
         let action_names = cx.all_action_names().collect::<Vec<_>>();
         project.set_language_server_settings(serde_json::json!({
             "json": {
@@ -161,7 +162,7 @@ pub fn build_workspace(
         }));
     });
 
-    let project_panel = ProjectPanel::new(project, cx);
+    let project_panel = ProjectPanel::new(workspace.project().clone(), cx);
     let contact_panel = cx.add_view(|cx| {
         ContactsPanel::new(app_state.user_store.clone(), workspace.weak_handle(), cx)
     });
@@ -186,8 +187,6 @@ pub fn build_workspace(
         status_bar.add_right_item(cursor_position, cx);
         status_bar.add_right_item(auto_update, cx);
     });
-
-    workspace
 }
 
 pub fn build_window_options() -> WindowOptions<'static> {
@@ -277,14 +276,18 @@ fn open_config_file(
                     workspace.open_paths(vec![path.to_path_buf()], cx)
                 } else {
                     let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| {
-                        let project = Project::local(
-                            app_state.client.clone(),
-                            app_state.user_store.clone(),
-                            app_state.languages.clone(),
-                            app_state.fs.clone(),
+                        let mut workspace = Workspace::new(
+                            Project::local(
+                                app_state.client.clone(),
+                                app_state.user_store.clone(),
+                                app_state.languages.clone(),
+                                app_state.fs.clone(),
+                                cx,
+                            ),
                             cx,
                         );
-                        (app_state.build_workspace)(project, &app_state, cx)
+                        (app_state.initialize_workspace)(&mut workspace, &app_state, cx);
+                        workspace
                     });
                     workspace.update(cx, |workspace, cx| {
                         workspace.open_paths(vec![path.to_path_buf()], cx)
@@ -1168,7 +1171,7 @@ mod tests {
         cx.update(|cx| {
             let mut app_state = AppState::test(cx);
             let state = Arc::get_mut(&mut app_state).unwrap();
-            state.build_workspace = build_workspace;
+            state.initialize_workspace = initialize_workspace;
             state.build_window_options = build_window_options;
             workspace::init(app_state.clone(), cx);
             editor::init(cx);