Wait for acknowledgment before sending the next project update

Antonio Scandurra created

Change summary

crates/call/src/room.rs                |   2 
crates/collab/src/db.rs                |  16 +
crates/collab/src/integration_tests.rs |  12 -
crates/collab/src/rpc.rs               |   6 
crates/collab_ui/src/collab_ui.rs      |   1 
crates/project/src/project.rs          | 218 ++++++++-------------------
crates/project/src/worktree.rs         |  19 --
crates/rpc/proto/zed.proto             |   7 
crates/rpc/src/proto.rs                |   9 
crates/workspace/src/workspace.rs      |   8 
crates/zed/src/main.rs                 |   4 
11 files changed, 94 insertions(+), 208 deletions(-)

Detailed changes

crates/call/src/room.rs 🔗

@@ -287,6 +287,8 @@ impl Room {
         mut room: proto::Room,
         cx: &mut ModelContext<Self>,
     ) -> Result<()> {
+        // TODO: honor room version.
+
         // Filter ourselves out from the room's participants.
         let local_participant_ix = room
             .participants

crates/collab/src/db.rs 🔗

@@ -1145,8 +1145,8 @@ where
                     FROM projects, project_collaborators
                     WHERE
                         projects.room_id = $1 AND
-                        projects.host_connection_id = $2 AND
-                        projects.id = project_collaborators.project_id
+                        projects.id = project_collaborators.project_id AND
+                        project_collaborators.connection_id = $2
                     ",
                 )
                 .bind(room_id)
@@ -1370,9 +1370,9 @@ where
 
     pub async fn share_project(
         &self,
+        room_id: RoomId,
         user_id: UserId,
         connection_id: ConnectionId,
-        room_id: RoomId,
         worktrees: &[proto::WorktreeMetadata],
     ) -> Result<(ProjectId, proto::Room)> {
         test_support!(self, {
@@ -1426,11 +1426,19 @@ where
             .await?;
 
             let room = self.commit_room_transaction(room_id, tx).await?;
-            dbg!(&room);
             Ok((project_id, room))
         })
     }
 
+    // pub async fn join_project(
+    //     &self,
+    //     user_id: UserId,
+    //     connection_id: ConnectionId,
+    //     project_id: ProjectId,
+    // ) -> Result<(Project, ReplicaId)> {
+    //     todo!()
+    // }
+
     pub async fn unshare_project(&self, project_id: ProjectId) -> Result<()> {
         todo!()
         // test_support!(self, {

crates/collab/src/integration_tests.rs 🔗

@@ -30,9 +30,7 @@ use language::{
 use live_kit_client::MacOSDisplay;
 use lsp::{self, FakeLanguageServer};
 use parking_lot::Mutex;
-use project::{
-    search::SearchQuery, DiagnosticSummary, Project, ProjectPath, ProjectStore, WorktreeId,
-};
+use project::{search::SearchQuery, DiagnosticSummary, Project, ProjectPath, WorktreeId};
 use rand::prelude::*;
 use serde_json::json;
 use settings::{Formatter, Settings};
@@ -2280,7 +2278,6 @@ async fn test_leaving_project(
             project_id,
             client_b.client.clone(),
             client_b.user_store.clone(),
-            client_b.project_store.clone(),
             client_b.language_registry.clone(),
             FakeFs::new(cx.background()),
             cx,
@@ -5792,11 +5789,9 @@ impl TestServer {
 
         let fs = FakeFs::new(cx.background());
         let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http, cx));
-        let project_store = cx.add_model(|_| ProjectStore::new());
         let app_state = Arc::new(workspace::AppState {
             client: client.clone(),
             user_store: user_store.clone(),
-            project_store: project_store.clone(),
             languages: Arc::new(LanguageRegistry::new(Task::ready(()))),
             themes: ThemeRegistry::new((), cx.font_cache()),
             fs: fs.clone(),
@@ -5823,7 +5818,6 @@ impl TestServer {
             remote_projects: Default::default(),
             next_root_dir_id: 0,
             user_store,
-            project_store,
             fs,
             language_registry: Arc::new(LanguageRegistry::test()),
             buffers: Default::default(),
@@ -5929,7 +5923,6 @@ struct TestClient {
     remote_projects: Vec<ModelHandle<Project>>,
     next_root_dir_id: usize,
     pub user_store: ModelHandle<UserStore>,
-    pub project_store: ModelHandle<ProjectStore>,
     language_registry: Arc<LanguageRegistry>,
     fs: Arc<FakeFs>,
     buffers: HashMap<ModelHandle<Project>, HashSet<ModelHandle<language::Buffer>>>,
@@ -5999,7 +5992,6 @@ impl TestClient {
             Project::local(
                 self.client.clone(),
                 self.user_store.clone(),
-                self.project_store.clone(),
                 self.language_registry.clone(),
                 self.fs.clone(),
                 cx,
@@ -6027,7 +6019,6 @@ impl TestClient {
                 host_project_id,
                 self.client.clone(),
                 self.user_store.clone(),
-                self.project_store.clone(),
                 self.language_registry.clone(),
                 FakeFs::new(cx.background()),
                 cx,
@@ -6157,7 +6148,6 @@ impl TestClient {
                             remote_project_id,
                             client.client.clone(),
                             client.user_store.clone(),
-                            client.project_store.clone(),
                             client.language_registry.clone(),
                             FakeFs::new(cx.background()),
                             cx.to_async(),

crates/collab/src/rpc.rs 🔗

@@ -151,7 +151,7 @@ impl Server {
             .add_message_handler(Server::unshare_project)
             .add_request_handler(Server::join_project)
             .add_message_handler(Server::leave_project)
-            .add_message_handler(Server::update_project)
+            .add_request_handler(Server::update_project)
             .add_request_handler(Server::update_worktree)
             .add_message_handler(Server::start_language_server)
             .add_message_handler(Server::update_language_server)
@@ -861,9 +861,9 @@ impl Server {
             .app_state
             .db
             .share_project(
+                RoomId::from_proto(request.payload.room_id),
                 request.sender_user_id,
                 request.sender_connection_id,
-                RoomId::from_proto(request.payload.room_id),
                 &request.payload.worktrees,
             )
             .await
@@ -1084,6 +1084,7 @@ impl Server {
     async fn update_project(
         self: Arc<Server>,
         request: Message<proto::UpdateProject>,
+        response: Response<proto::UpdateProject>,
     ) -> Result<()> {
         let project_id = ProjectId::from_proto(request.payload.project_id);
         {
@@ -1108,6 +1109,7 @@ impl Server {
                 },
             );
             self.room_updated(room);
+            response.send(proto::Ack {})?;
         };
 
         Ok(())

crates/collab_ui/src/collab_ui.rs 🔗

@@ -43,7 +43,6 @@ pub fn init(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
                     project_id,
                     app_state.client.clone(),
                     app_state.user_store.clone(),
-                    app_state.project_store.clone(),
                     app_state.languages.clone(),
                     app_state.fs.clone(),
                     cx.clone(),

crates/project/src/project.rs 🔗

@@ -70,10 +70,6 @@ pub trait Item: Entity {
     fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
 }
 
-pub struct ProjectStore {
-    projects: Vec<WeakModelHandle<Project>>,
-}
-
 // Language server state is stored across 3 collections:
 //     language_servers =>
 //         a mapping from unique server id to LanguageServerState which can either be a task for a
@@ -102,7 +98,6 @@ pub struct Project {
     next_entry_id: Arc<AtomicUsize>,
     next_diagnostic_group_id: usize,
     user_store: ModelHandle<UserStore>,
-    project_store: ModelHandle<ProjectStore>,
     fs: Arc<dyn Fs>,
     client_state: Option<ProjectClientState>,
     collaborators: HashMap<PeerId, Collaborator>,
@@ -152,6 +147,8 @@ enum WorktreeHandle {
 enum ProjectClientState {
     Local {
         remote_id: u64,
+        metadata_changed: watch::Sender<()>,
+        _maintain_metadata: Task<()>,
         _detect_unshare: Task<Option<()>>,
     },
     Remote {
@@ -376,7 +373,7 @@ impl Project {
         client.add_model_message_handler(Self::handle_start_language_server);
         client.add_model_message_handler(Self::handle_update_language_server);
         client.add_model_message_handler(Self::handle_remove_collaborator);
-        client.add_model_message_handler(Self::handle_update_project);
+        client.add_model_message_handler(Self::handle_project_updated);
         client.add_model_message_handler(Self::handle_unshare_project);
         client.add_model_message_handler(Self::handle_create_buffer_for_peer);
         client.add_model_message_handler(Self::handle_update_buffer_file);
@@ -412,46 +409,39 @@ impl Project {
     pub fn local(
         client: Arc<Client>,
         user_store: ModelHandle<UserStore>,
-        project_store: ModelHandle<ProjectStore>,
         languages: Arc<LanguageRegistry>,
         fs: Arc<dyn Fs>,
         cx: &mut MutableAppContext,
     ) -> ModelHandle<Self> {
-        cx.add_model(|cx: &mut ModelContext<Self>| {
-            let handle = cx.weak_handle();
-            project_store.update(cx, |store, cx| store.add_project(handle, cx));
-
-            Self {
-                worktrees: Default::default(),
-                collaborators: Default::default(),
-                opened_buffers: Default::default(),
-                shared_buffers: Default::default(),
-                incomplete_buffers: Default::default(),
-                loading_buffers: Default::default(),
-                loading_local_worktrees: Default::default(),
-                buffer_snapshots: Default::default(),
-                client_state: None,
-                opened_buffer: watch::channel(),
-                client_subscriptions: Vec::new(),
-                _subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
-                _maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
-                active_entry: None,
-                languages,
-                client,
-                user_store,
-                project_store,
-                fs,
-                next_entry_id: Default::default(),
-                next_diagnostic_group_id: Default::default(),
-                language_servers: Default::default(),
-                language_server_ids: Default::default(),
-                language_server_statuses: Default::default(),
-                last_workspace_edits_by_language_server: Default::default(),
-                language_server_settings: Default::default(),
-                buffers_being_formatted: Default::default(),
-                next_language_server_id: 0,
-                nonce: StdRng::from_entropy().gen(),
-            }
+        cx.add_model(|cx: &mut ModelContext<Self>| Self {
+            worktrees: Default::default(),
+            collaborators: Default::default(),
+            opened_buffers: Default::default(),
+            shared_buffers: Default::default(),
+            incomplete_buffers: Default::default(),
+            loading_buffers: Default::default(),
+            loading_local_worktrees: Default::default(),
+            buffer_snapshots: Default::default(),
+            client_state: None,
+            opened_buffer: watch::channel(),
+            client_subscriptions: Vec::new(),
+            _subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
+            _maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
+            active_entry: None,
+            languages,
+            client,
+            user_store,
+            fs,
+            next_entry_id: Default::default(),
+            next_diagnostic_group_id: Default::default(),
+            language_servers: Default::default(),
+            language_server_ids: Default::default(),
+            language_server_statuses: Default::default(),
+            last_workspace_edits_by_language_server: Default::default(),
+            language_server_settings: Default::default(),
+            buffers_being_formatted: Default::default(),
+            next_language_server_id: 0,
+            nonce: StdRng::from_entropy().gen(),
         })
     }
 
@@ -459,7 +449,6 @@ impl Project {
         remote_id: u64,
         client: Arc<Client>,
         user_store: ModelHandle<UserStore>,
-        project_store: ModelHandle<ProjectStore>,
         languages: Arc<LanguageRegistry>,
         fs: Arc<dyn Fs>,
         mut cx: AsyncAppContext,
@@ -482,9 +471,6 @@ impl Project {
         }
 
         let this = cx.add_model(|cx: &mut ModelContext<Self>| {
-            let handle = cx.weak_handle();
-            project_store.update(cx, |store, cx| store.add_project(handle, cx));
-
             let mut this = Self {
                 worktrees: Vec::new(),
                 loading_buffers: Default::default(),
@@ -497,7 +483,6 @@ impl Project {
                 _maintain_buffer_languages: Self::maintain_buffer_languages(&languages, cx),
                 languages,
                 user_store: user_store.clone(),
-                project_store,
                 fs,
                 next_entry_id: Default::default(),
                 next_diagnostic_group_id: Default::default(),
@@ -593,9 +578,7 @@ impl Project {
         let http_client = client::test::FakeHttpClient::with_404_response();
         let client = cx.update(|cx| client::Client::new(http_client.clone(), cx));
         let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
-        let project_store = cx.add_model(|_| ProjectStore::new());
-        let project =
-            cx.update(|cx| Project::local(client, user_store, project_store, languages, fs, cx));
+        let project = cx.update(|cx| Project::local(client, user_store, languages, fs, cx));
         for path in root_paths {
             let (tree, _) = project
                 .update(cx, |project, cx| {
@@ -676,10 +659,6 @@ impl Project {
         self.user_store.clone()
     }
 
-    pub fn project_store(&self) -> ModelHandle<ProjectStore> {
-        self.project_store.clone()
-    }
-
     #[cfg(any(test, feature = "test-support"))]
     pub fn check_invariants(&self, cx: &AppContext) {
         if self.is_local() {
@@ -752,51 +731,12 @@ impl Project {
     }
 
     fn metadata_changed(&mut self, cx: &mut ModelContext<Self>) {
-        if let Some(ProjectClientState::Local { remote_id, .. }) = &self.client_state {
-            let project_id = *remote_id;
-            // Broadcast worktrees only if the project is online.
-            let worktrees = self
-                .worktrees
-                .iter()
-                .filter_map(|worktree| {
-                    worktree
-                        .upgrade(cx)
-                        .map(|worktree| worktree.read(cx).as_local().unwrap().metadata_proto())
-                })
-                .collect();
-            self.client
-                .send(proto::UpdateProject {
-                    project_id,
-                    worktrees,
-                })
-                .log_err();
-
-            let worktrees = self.visible_worktrees(cx).collect::<Vec<_>>();
-            let scans_complete = futures::future::join_all(
-                worktrees
-                    .iter()
-                    .filter_map(|worktree| Some(worktree.read(cx).as_local()?.scan_complete())),
-            );
-
-            let worktrees = worktrees.into_iter().map(|handle| handle.downgrade());
-
-            cx.spawn_weak(move |_, cx| async move {
-                scans_complete.await;
-                cx.read(|cx| {
-                    for worktree in worktrees {
-                        if let Some(worktree) = worktree
-                            .upgrade(cx)
-                            .and_then(|worktree| worktree.read(cx).as_local())
-                        {
-                            worktree.send_extension_counts(project_id);
-                        }
-                    }
-                })
-            })
-            .detach();
+        if let Some(ProjectClientState::Local {
+            metadata_changed, ..
+        }) = &mut self.client_state
+        {
+            *metadata_changed.borrow_mut() = ();
         }
-
-        self.project_store.update(cx, |_, cx| cx.notify());
         cx.notify();
     }
 
@@ -1092,8 +1032,32 @@ impl Project {
         cx.notify();
 
         let mut status = self.client.status();
+        let (metadata_changed_tx, mut metadata_changed_rx) = watch::channel();
         self.client_state = Some(ProjectClientState::Local {
             remote_id: project_id,
+            metadata_changed: metadata_changed_tx,
+            _maintain_metadata: cx.spawn_weak(move |this, cx| async move {
+                while let Some(()) = metadata_changed_rx.next().await {
+                    let Some(this) = this.upgrade(&cx) else { break };
+                    this.read_with(&cx, |this, cx| {
+                        let worktrees = this
+                            .worktrees
+                            .iter()
+                            .filter_map(|worktree| {
+                                worktree.upgrade(cx).map(|worktree| {
+                                    worktree.read(cx).as_local().unwrap().metadata_proto()
+                                })
+                            })
+                            .collect();
+                        this.client.request(proto::UpdateProject {
+                            project_id,
+                            worktrees,
+                        })
+                    })
+                    .await
+                    .log_err();
+                }
+            }),
             _detect_unshare: cx.spawn_weak(move |this, mut cx| {
                 async move {
                     let is_connected = status.next().await.map_or(false, |s| s.is_connected());
@@ -1632,10 +1596,6 @@ impl Project {
                         operations: vec![language::proto::serialize_operation(operation)],
                     });
                     cx.background().spawn(request).detach_and_log_err(cx);
-                } else if let Some(project_id) = self.remote_id() {
-                    let _ = self
-                        .client
-                        .send(proto::RegisterProjectActivity { project_id });
                 }
             }
             BufferEvent::Edited { .. } => {
@@ -4573,9 +4533,9 @@ impl Project {
         })
     }
 
-    async fn handle_update_project(
+    async fn handle_project_updated(
         this: ModelHandle<Self>,
-        envelope: TypedEnvelope<proto::UpdateProject>,
+        envelope: TypedEnvelope<proto::ProjectUpdated>,
         client: Arc<Client>,
         mut cx: AsyncAppContext,
     ) -> Result<()> {
@@ -5832,48 +5792,6 @@ impl Project {
     }
 }
 
-impl ProjectStore {
-    pub fn new() -> Self {
-        Self {
-            projects: Default::default(),
-        }
-    }
-
-    pub fn projects<'a>(
-        &'a self,
-        cx: &'a AppContext,
-    ) -> impl 'a + Iterator<Item = ModelHandle<Project>> {
-        self.projects
-            .iter()
-            .filter_map(|project| project.upgrade(cx))
-    }
-
-    fn add_project(&mut self, project: WeakModelHandle<Project>, cx: &mut ModelContext<Self>) {
-        if let Err(ix) = self
-            .projects
-            .binary_search_by_key(&project.id(), WeakModelHandle::id)
-        {
-            self.projects.insert(ix, project);
-        }
-        cx.notify();
-    }
-
-    fn prune_projects(&mut self, cx: &mut ModelContext<Self>) {
-        let mut did_change = false;
-        self.projects.retain(|project| {
-            if project.is_upgradable(cx) {
-                true
-            } else {
-                did_change = true;
-                false
-            }
-        });
-        if did_change {
-            cx.notify();
-        }
-    }
-}
-
 impl WorktreeHandle {
     pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
         match self {
@@ -5952,16 +5870,10 @@ impl<'a> Iterator for PathMatchCandidateSetIter<'a> {
     }
 }
 
-impl Entity for ProjectStore {
-    type Event = ();
-}
-
 impl Entity for Project {
     type Event = Event;
 
-    fn release(&mut self, cx: &mut gpui::MutableAppContext) {
-        self.project_store.update(cx, ProjectStore::prune_projects);
-
+    fn release(&mut self, _: &mut gpui::MutableAppContext) {
         match &self.client_state {
             Some(ProjectClientState::Local { remote_id, .. }) => {
                 self.client

crates/project/src/worktree.rs 🔗

@@ -1051,25 +1051,6 @@ impl LocalWorktree {
     pub fn is_shared(&self) -> bool {
         self.share.is_some()
     }
-
-    pub fn send_extension_counts(&self, project_id: u64) {
-        let mut extensions = Vec::new();
-        let mut counts = Vec::new();
-
-        for (extension, count) in self.extension_counts() {
-            extensions.push(extension.to_string_lossy().to_string());
-            counts.push(*count as u32);
-        }
-
-        self.client
-            .send(proto::UpdateWorktreeExtensions {
-                project_id,
-                worktree_id: self.id().to_proto(),
-                extensions,
-                counts,
-            })
-            .log_err();
-    }
 }
 
 impl RemoteWorktree {

crates/rpc/proto/zed.proto 🔗

@@ -48,9 +48,8 @@ message Envelope {
         OpenBufferForSymbolResponse open_buffer_for_symbol_response = 40;
 
         UpdateProject update_project = 41;
-        RegisterProjectActivity register_project_activity = 42;
+        ProjectUpdated project_updated = 42;
         UpdateWorktree update_worktree = 43;
-        UpdateWorktreeExtensions update_worktree_extensions = 44;
 
         CreateProjectEntry create_project_entry = 45;
         RenameProjectEntry rename_project_entry = 46;
@@ -258,8 +257,10 @@ message UpdateProject {
     repeated WorktreeMetadata worktrees = 2;
 }
 
-message RegisterProjectActivity {
+message ProjectUpdated {
     uint64 project_id = 1;
+    repeated WorktreeMetadata worktrees = 2;
+    uint64 room_version = 3;
 }
 
 message JoinProject {

crates/rpc/src/proto.rs 🔗

@@ -140,12 +140,12 @@ messages!(
     (OpenBufferResponse, Background),
     (PerformRename, Background),
     (PerformRenameResponse, Background),
+    (Ping, Foreground),
     (PrepareRename, Background),
     (PrepareRenameResponse, Background),
     (ProjectEntryResponse, Foreground),
+    (ProjectUpdated, Foreground),
     (RemoveContact, Foreground),
-    (Ping, Foreground),
-    (RegisterProjectActivity, Foreground),
     (ReloadBuffers, Foreground),
     (ReloadBuffersResponse, Foreground),
     (RemoveProjectCollaborator, Foreground),
@@ -175,7 +175,6 @@ messages!(
     (UpdateParticipantLocation, Foreground),
     (UpdateProject, Foreground),
     (UpdateWorktree, Foreground),
-    (UpdateWorktreeExtensions, Background),
     (UpdateDiffBase, Background),
     (GetPrivateUserInfo, Foreground),
     (GetPrivateUserInfoResponse, Foreground),
@@ -231,6 +230,7 @@ request_messages!(
     (Test, Test),
     (UpdateBuffer, Ack),
     (UpdateParticipantLocation, Ack),
+    (UpdateProject, Ack),
     (UpdateWorktree, Ack),
 );
 
@@ -261,8 +261,8 @@ entity_messages!(
     OpenBufferByPath,
     OpenBufferForSymbol,
     PerformRename,
+    ProjectUpdated,
     PrepareRename,
-    RegisterProjectActivity,
     ReloadBuffers,
     RemoveProjectCollaborator,
     RenameProjectEntry,
@@ -278,7 +278,6 @@ entity_messages!(
     UpdateLanguageServer,
     UpdateProject,
     UpdateWorktree,
-    UpdateWorktreeExtensions,
     UpdateDiffBase
 );
 

crates/workspace/src/workspace.rs 🔗

@@ -33,7 +33,7 @@ use log::{error, warn};
 pub use pane::*;
 pub use pane_group::*;
 use postage::prelude::Stream;
-use project::{Project, ProjectEntryId, ProjectPath, ProjectStore, Worktree, WorktreeId};
+use project::{Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId};
 use searchable::SearchableItemHandle;
 use serde::Deserialize;
 use settings::{Autosave, DockAnchor, Settings};
@@ -337,7 +337,6 @@ pub struct AppState {
     pub themes: Arc<ThemeRegistry>,
     pub client: Arc<client::Client>,
     pub user_store: ModelHandle<client::UserStore>,
-    pub project_store: ModelHandle<ProjectStore>,
     pub fs: Arc<dyn fs::Fs>,
     pub build_window_options: fn() -> WindowOptions<'static>,
     pub initialize_workspace: fn(&mut Workspace, &Arc<AppState>, &mut ViewContext<Workspace>),
@@ -1039,7 +1038,6 @@ impl AppState {
         let languages = Arc::new(LanguageRegistry::test());
         let http_client = client::test::FakeHttpClient::with_404_response();
         let client = Client::new(http_client.clone(), cx);
-        let project_store = cx.add_model(|_| ProjectStore::new());
         let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
         let themes = ThemeRegistry::new((), cx.font_cache().clone());
         Arc::new(Self {
@@ -1048,7 +1046,6 @@ impl AppState {
             fs,
             languages,
             user_store,
-            project_store,
             initialize_workspace: |_, _, _| {},
             build_window_options: Default::default,
             default_item_factory: |_, _| unimplemented!(),
@@ -1301,7 +1298,6 @@ impl Workspace {
                     Project::local(
                         app_state.client.clone(),
                         app_state.user_store.clone(),
-                        app_state.project_store.clone(),
                         app_state.languages.clone(),
                         app_state.fs.clone(),
                         cx,
@@ -2965,7 +2961,6 @@ pub fn open_paths(
                 let project = Project::local(
                     app_state.client.clone(),
                     app_state.user_store.clone(),
-                    app_state.project_store.clone(),
                     app_state.languages.clone(),
                     app_state.fs.clone(),
                     cx,
@@ -2997,7 +2992,6 @@ fn open_new(app_state: &Arc<AppState>, cx: &mut MutableAppContext) {
             Project::local(
                 app_state.client.clone(),
                 app_state.user_store.clone(),
-                app_state.project_store.clone(),
                 app_state.languages.clone(),
                 app_state.fs.clone(),
                 cx,

crates/zed/src/main.rs 🔗

@@ -23,7 +23,7 @@ use isahc::{config::Configurable, Request};
 use language::LanguageRegistry;
 use log::LevelFilter;
 use parking_lot::Mutex;
-use project::{Fs, HomeDir, ProjectStore};
+use project::{Fs, HomeDir};
 use serde_json::json;
 use settings::{
     self, settings_file::SettingsFile, KeymapFileContent, Settings, SettingsFileContent,
@@ -146,7 +146,6 @@ fn main() {
         })
         .detach();
 
-        let project_store = cx.add_model(|_| ProjectStore::new());
         let db = cx.background().block(db);
         client.start_telemetry(db.clone());
         client.report_event("start app", Default::default());
@@ -156,7 +155,6 @@ fn main() {
             themes,
             client: client.clone(),
             user_store,
-            project_store,
             fs,
             build_window_options,
             initialize_workspace,