Get integration test passing. Wait for expand entry on remote projects.

Max Brunsfeld created

Change summary

crates/collab/src/tests/integration_tests.rs | 21 +++++
crates/project/src/project.rs                | 79 ++++++++++++---------
crates/project/src/worktree.rs               | 24 ++---
crates/project_panel/src/project_panel.rs    |  6 
crates/rpc/proto/zed.proto                   |  7 +
crates/rpc/src/proto.rs                      |  3 
6 files changed, 88 insertions(+), 52 deletions(-)

Detailed changes

crates/collab/src/tests/integration_tests.rs 🔗

@@ -1266,6 +1266,27 @@ async fn test_share_project(
         let client_b_collaborator = project.collaborators().get(&client_b_peer_id).unwrap();
         assert_eq!(client_b_collaborator.replica_id, replica_id_b);
     });
+    project_b.read_with(cx_b, |project, cx| {
+        let worktree = project.worktrees(cx).next().unwrap().read(cx);
+        assert_eq!(
+            worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
+            [
+                Path::new(".gitignore"),
+                Path::new("a.txt"),
+                Path::new("b.txt"),
+                Path::new("ignored-dir"),
+            ]
+        );
+    });
+
+    project_b
+        .update(cx_b, |project, cx| {
+            let worktree = project.worktrees(cx).next().unwrap();
+            let entry = worktree.read(cx).entry_for_path("ignored-dir").unwrap();
+            project.expand_entry(worktree_id, entry.id, cx).unwrap()
+        })
+        .await
+        .unwrap();
     project_b.read_with(cx_b, |project, cx| {
         let worktree = project.worktrees(cx).next().unwrap().read(cx);
         assert_eq!(

crates/project/src/project.rs 🔗

@@ -1073,6 +1073,40 @@ impl Project {
         }
     }
 
+    pub fn expand_entry(
+        &mut self,
+        worktree_id: WorktreeId,
+        entry_id: ProjectEntryId,
+        cx: &mut ModelContext<Self>,
+    ) -> Option<Task<Result<()>>> {
+        let worktree = self.worktree_for_id(worktree_id, cx)?;
+        if self.is_local() {
+            worktree.update(cx, |worktree, cx| {
+                worktree.as_local_mut().unwrap().expand_entry(entry_id, cx)
+            })
+        } else {
+            let worktree = worktree.downgrade();
+            let request = self.client.request(proto::ExpandProjectEntry {
+                project_id: self.remote_id().unwrap(),
+                entry_id: entry_id.to_proto(),
+            });
+            Some(cx.spawn_weak(|_, mut cx| async move {
+                let response = request.await?;
+                if let Some(worktree) = worktree.upgrade(&cx) {
+                    worktree
+                        .update(&mut cx, |worktree, _| {
+                            worktree
+                                .as_remote_mut()
+                                .unwrap()
+                                .wait_for_snapshot(response.worktree_scan_id as usize)
+                        })
+                        .await?;
+                }
+                Ok(())
+            }))
+        }
+    }
+
     pub fn shared(&mut self, project_id: u64, cx: &mut ModelContext<Self>) -> Result<()> {
         if self.client_state.is_some() {
             return Err(anyhow!("project was already shared"));
@@ -5404,31 +5438,6 @@ impl Project {
         Some(ProjectPath { worktree_id, path })
     }
 
-    pub fn mark_entry_expanded(
-        &mut self,
-        worktree_id: WorktreeId,
-        entry_id: ProjectEntryId,
-        cx: &mut ModelContext<Self>,
-    ) -> Option<()> {
-        if self.is_local() {
-            let worktree = self.worktree_for_id(worktree_id, cx)?;
-            worktree.update(cx, |worktree, cx| {
-                worktree
-                    .as_local_mut()
-                    .unwrap()
-                    .expand_entry_for_id(entry_id, cx);
-            });
-        } else if let Some(project_id) = self.remote_id() {
-            cx.background()
-                .spawn(self.client.request(proto::ExpandProjectEntry {
-                    project_id,
-                    entry_id: entry_id.to_proto(),
-                }))
-                .log_err();
-        }
-        Some(())
-    }
-
     pub fn absolute_path(&self, project_path: &ProjectPath, cx: &AppContext) -> Option<PathBuf> {
         let workspace_root = self
             .worktree_for_id(project_path.worktree_id, cx)?
@@ -5736,18 +5745,22 @@ impl Project {
         envelope: TypedEnvelope<proto::ExpandProjectEntry>,
         _: Arc<Client>,
         mut cx: AsyncAppContext,
-    ) -> Result<proto::Ack> {
+    ) -> Result<proto::ExpandProjectEntryResponse> {
         let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
         let worktree = this
             .read_with(&cx, |this, cx| this.worktree_for_entry(entry_id, cx))
             .ok_or_else(|| anyhow!("invalid request"))?;
-        worktree.update(&mut cx, |worktree, cx| {
-            worktree
-                .as_local_mut()
-                .unwrap()
-                .expand_entry_for_id(entry_id, cx)
-        });
-        Ok(proto::Ack {})
+        worktree
+            .update(&mut cx, |worktree, cx| {
+                worktree
+                    .as_local_mut()
+                    .unwrap()
+                    .expand_entry(entry_id, cx)
+                    .ok_or_else(|| anyhow!("invalid entry"))
+            })?
+            .await?;
+        let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id()) as u64;
+        Ok(proto::ExpandProjectEntryResponse { worktree_scan_id })
     }
 
     async fn handle_update_diagnostic_summary(

crates/project/src/worktree.rs 🔗

@@ -1127,21 +1127,17 @@ impl LocalWorktree {
         }))
     }
 
-    pub fn expand_entry_for_id(
+    pub fn expand_entry(
         &mut self,
         entry_id: ProjectEntryId,
-        _cx: &mut ModelContext<Worktree>,
-    ) -> barrier::Receiver {
-        let (tx, rx) = barrier::channel();
-        if let Some(entry) = self.entry_for_id(entry_id) {
-            self.scan_requests_tx
-                .try_send(ScanRequest {
-                    relative_paths: vec![entry.path.clone()],
-                    done: tx,
-                })
-                .ok();
-        }
-        rx
+        cx: &mut ModelContext<Worktree>,
+    ) -> Option<Task<Result<()>>> {
+        let path = self.entry_for_id(entry_id)?.path.clone();
+        let mut refresh = self.refresh_entries_for_paths(vec![path]);
+        Some(cx.background().spawn(async move {
+            refresh.next().await;
+            Ok(())
+        }))
     }
 
     pub fn refresh_entries_for_paths(&self, paths: Vec<Arc<Path>>) -> barrier::Receiver {
@@ -1337,7 +1333,7 @@ impl RemoteWorktree {
         self.completed_scan_id >= scan_id
     }
 
-    fn wait_for_snapshot(&mut self, scan_id: usize) -> impl Future<Output = Result<()>> {
+    pub(crate) fn wait_for_snapshot(&mut self, scan_id: usize) -> impl Future<Output = Result<()>> {
         let (tx, rx) = oneshot::channel();
         if self.observed_snapshot(scan_id) {
             let _ = tx.send(());

crates/project_panel/src/project_panel.rs 🔗

@@ -423,7 +423,7 @@ impl ProjectPanel {
                     Ok(_) => self.select_next(&SelectNext, cx),
                     Err(ix) => {
                         self.project.update(cx, |project, cx| {
-                            project.mark_entry_expanded(worktree_id, entry_id, cx);
+                            project.expand_entry(worktree_id, entry_id, cx);
                         });
 
                         expanded_dir_ids.insert(ix, entry_id);
@@ -477,7 +477,7 @@ impl ProjectPanel {
                             expanded_dir_ids.remove(ix);
                         }
                         Err(ix) => {
-                            project.mark_entry_expanded(worktree_id, entry_id, cx);
+                            project.expand_entry(worktree_id, entry_id, cx);
                             expanded_dir_ids.insert(ix, entry_id);
                         }
                     }
@@ -1084,7 +1084,7 @@ impl ProjectPanel {
                 .worktree_for_id(worktree_id, cx)
                 .zip(self.expanded_dir_ids.get_mut(&worktree_id))
             {
-                project.mark_entry_expanded(worktree_id, entry_id, cx);
+                project.expand_entry(worktree_id, entry_id, cx);
                 let worktree = worktree.read(cx);
 
                 if let Some(mut entry) = worktree.entry_for_id(entry_id) {

crates/rpc/proto/zed.proto 🔗

@@ -62,8 +62,9 @@ message Envelope {
         RenameProjectEntry rename_project_entry = 46;
         CopyProjectEntry copy_project_entry = 47;
         DeleteProjectEntry delete_project_entry = 48;
-        ExpandProjectEntry expand_project_entry = 114;
         ProjectEntryResponse project_entry_response = 49;
+        ExpandProjectEntry expand_project_entry = 114;
+        ExpandProjectEntryResponse expand_project_entry_response = 115;
 
         UpdateDiagnosticSummary update_diagnostic_summary = 50;
         StartLanguageServer start_language_server = 51;
@@ -378,6 +379,10 @@ message ExpandProjectEntry {
     uint64 entry_id = 2;
 }
 
+message ExpandProjectEntryResponse {
+    uint64 worktree_scan_id = 1;
+}
+
 message ProjectEntryResponse {
     Entry entry = 1;
     uint64 worktree_scan_id = 2;

crates/rpc/src/proto.rs 🔗

@@ -201,6 +201,7 @@ messages!(
     (Ping, Foreground),
     (PrepareRename, Background),
     (PrepareRenameResponse, Background),
+    (ExpandProjectEntryResponse, Foreground),
     (ProjectEntryResponse, Foreground),
     (RejoinRoom, Foreground),
     (RejoinRoomResponse, Foreground),
@@ -256,7 +257,7 @@ request_messages!(
     (CreateRoom, CreateRoomResponse),
     (DeclineCall, Ack),
     (DeleteProjectEntry, ProjectEntryResponse),
-    (ExpandProjectEntry, Ack),
+    (ExpandProjectEntry, ExpandProjectEntryResponse),
     (Follow, FollowResponse),
     (FormatBuffers, FormatBuffersResponse),
     (GetChannelMessages, GetChannelMessagesResponse),