diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index faf1da297d..cfea7cbc16 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -127,6 +127,7 @@ impl Server { .add_request_handler(Server::forward_project_request::) .add_request_handler(Server::forward_project_request::) .add_request_handler(Server::forward_project_request::) + .add_request_handler(Server::forward_project_request::) .add_request_handler(Server::update_buffer) .add_message_handler(Server::update_buffer_file) .add_message_handler(Server::buffer_reloaded) @@ -1810,7 +1811,7 @@ mod tests { } #[gpui::test(iterations = 10)] - async fn test_worktree_manipulation( + async fn test_fs_operations( executor: Arc, cx_a: &mut TestAppContext, cx_b: &mut TestAppContext, @@ -1848,14 +1849,12 @@ mod tests { let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap()); - project_b + let entry = project_b .update(cx_b, |project, cx| { project.create_file((worktree_id, "c.txt"), cx).unwrap() }) .await .unwrap(); - - executor.run_until_parked(); worktree_a.read_with(cx_a, |worktree, _| { assert_eq!( worktree @@ -1874,6 +1873,32 @@ mod tests { [".zed.toml", "a.txt", "b.txt", "c.txt"] ); }); + + project_b + .update(cx_b, |project, cx| { + project.rename_entry(entry.id, Path::new("d.txt"), cx) + }) + .unwrap() + .await + .unwrap(); + worktree_a.read_with(cx_a, |worktree, _| { + assert_eq!( + worktree + .paths() + .map(|p| p.to_string_lossy()) + .collect::>(), + [".zed.toml", "a.txt", "b.txt", "d.txt"] + ); + }); + worktree_b.read_with(cx_b, |worktree, _| { + assert_eq!( + worktree + .paths() + .map(|p| p.to_string_lossy()) + .collect::>(), + [".zed.toml", "a.txt", "b.txt", "d.txt"] + ); + }); } #[gpui::test(iterations = 10)] diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index ea95a6e91d..7d1aacdde9 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -262,6 +262,7 @@ impl Project { client.add_model_message_handler(Self::handle_update_diagnostic_summary); client.add_model_message_handler(Self::handle_update_worktree); client.add_model_request_handler(Self::handle_create_project_entry); + client.add_model_request_handler(Self::handle_rename_project_entry); client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion); client.add_model_request_handler(Self::handle_apply_code_action); client.add_model_request_handler(Self::handle_reload_buffers); @@ -736,9 +737,9 @@ impl Project { new_path: impl Into>, cx: &mut ModelContext, ) -> Option>> { + let worktree = self.worktree_for_entry(entry_id, cx)?; + let new_path = new_path.into(); if self.is_local() { - let worktree = self.worktree_for_entry(entry_id, cx)?; - worktree.update(cx, |worktree, cx| { worktree .as_local_mut() @@ -746,7 +747,27 @@ impl Project { .rename_entry(entry_id, new_path, cx) }) } else { - todo!() + let client = self.client.clone(); + let project_id = self.remote_id().unwrap(); + + Some(cx.spawn_weak(|_, mut cx| async move { + let response = client + .request(proto::RenameProjectEntry { + project_id, + entry_id: entry_id.to_proto(), + new_path: new_path.as_os_str().as_bytes().to_vec(), + }) + .await?; + worktree.update(&mut cx, |worktree, _| { + let worktree = worktree.as_remote_mut().unwrap(); + worktree.snapshot.remove_entry(entry_id); + worktree.snapshot.insert_entry( + response + .entry + .ok_or_else(|| anyhow!("missing entry in response"))?, + ) + }) + })) } } @@ -3802,7 +3823,7 @@ impl Project { envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, - ) -> Result { + ) -> Result { let entry = this .update(&mut cx, |this, cx| { let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); @@ -3820,7 +3841,26 @@ impl Project { }) })? .await?; - Ok(proto::CreateProjectEntryResponse { + Ok(proto::ProjectEntryResponse { + entry: Some((&entry).into()), + }) + } + + async fn handle_rename_project_entry( + this: ModelHandle, + envelope: TypedEnvelope, + _: Arc, + mut cx: AsyncAppContext, + ) -> Result { + let entry = this + .update(&mut cx, |this, cx| { + let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id); + let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path)); + this.rename_entry(entry_id, new_path, cx) + .ok_or_else(|| anyhow!("invalid entry")) + })? + .await?; + Ok(proto::ProjectEntryResponse { entry: Some((&entry).into()), }) } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 65d5871bb6..7b3c700911 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -956,6 +956,14 @@ impl Snapshot { self.entries_by_id.get(&entry_id, &()).is_some() } + pub(crate) fn remove_entry(&mut self, entry_id: ProjectEntryId) -> Option { + if let Some(entry) = self.entries_by_id.remove(&entry_id, &()) { + self.entries_by_path.remove(&PathKey(entry.path), &()) + } else { + None + } + } + pub(crate) fn insert_entry(&mut self, entry: proto::Entry) -> Result { let entry = Entry::try_from((&self.root_char_bag, entry))?; self.entries_by_id.insert_or_replace( diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index dba6ce1037..5c96a254e5 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -295,11 +295,6 @@ impl ProjectPanel { Ok(()) })) } else { - // TODO - implement this for remote projects - if !worktree.read(cx).is_local() { - return None; - } - let old_path = entry.path.clone(); let new_path = if let Some(parent) = old_path.parent() { parent.join(filename) diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 3fc350e9b6..ffa2443537 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -38,9 +38,9 @@ message Envelope { UpdateWorktree update_worktree = 31; CreateProjectEntry create_project_entry = 32; - CreateProjectEntryResponse create_project_entry_response = 33; - RenameProjectEntry rename_project_entry = 34; - DeleteProjectEntry delete_project_entry = 35; + RenameProjectEntry rename_project_entry = 33; + DeleteProjectEntry delete_project_entry = 34; + ProjectEntryResponse project_entry_response = 35; UpdateDiagnosticSummary update_diagnostic_summary = 36; StartLanguageServer start_language_server = 37; @@ -171,16 +171,10 @@ message CreateProjectEntry { bool is_directory = 4; } -message CreateProjectEntryResponse { - Entry entry = 1; -} - message RenameProjectEntry { uint64 project_id = 1; - uint64 old_worktree_id = 2; - string old_path = 3; - uint64 new_worktree_id = 4; - string new_path = 5; + uint64 entry_id = 2; + bytes new_path = 3; } message DeleteProjectEntry { @@ -189,6 +183,10 @@ message DeleteProjectEntry { string path = 3; } +message ProjectEntryResponse { + Entry entry = 1; +} + message AddProjectCollaborator { uint64 project_id = 1; Collaborator collaborator = 2; diff --git a/crates/rpc/src/proto.rs b/crates/rpc/src/proto.rs index a1c28075f5..b2bcaa7d5f 100644 --- a/crates/rpc/src/proto.rs +++ b/crates/rpc/src/proto.rs @@ -148,7 +148,6 @@ messages!( (BufferSaved, Foreground), (ChannelMessageSent, Foreground), (CreateProjectEntry, Foreground), - (CreateProjectEntryResponse, Foreground), (DeleteProjectEntry, Foreground), (Error, Foreground), (Follow, Foreground), @@ -177,8 +176,6 @@ messages!( (JoinChannelResponse, Foreground), (JoinProject, Foreground), (JoinProjectResponse, Foreground), - (StartLanguageServer, Foreground), - (UpdateLanguageServer, Foreground), (LeaveChannel, Foreground), (LeaveProject, Foreground), (OpenBufferById, Background), @@ -190,6 +187,7 @@ messages!( (PerformRenameResponse, Background), (PrepareRename, Background), (PrepareRenameResponse, Background), + (ProjectEntryResponse, Foreground), (RegisterProjectResponse, Foreground), (Ping, Foreground), (RegisterProject, Foreground), @@ -204,6 +202,7 @@ messages!( (SendChannelMessage, Foreground), (SendChannelMessageResponse, Foreground), (ShareProject, Foreground), + (StartLanguageServer, Foreground), (Test, Foreground), (Unfollow, Foreground), (UnregisterProject, Foreground), @@ -214,6 +213,7 @@ messages!( (UpdateContacts, Foreground), (UpdateDiagnosticSummary, Foreground), (UpdateFollowers, Foreground), + (UpdateLanguageServer, Foreground), (UpdateWorktree, Foreground), ); @@ -223,7 +223,7 @@ request_messages!( ApplyCompletionAdditionalEdits, ApplyCompletionAdditionalEditsResponse ), - (CreateProjectEntry, CreateProjectEntryResponse), + (CreateProjectEntry, ProjectEntryResponse), (Follow, FollowResponse), (FormatBuffers, FormatBuffersResponse), (GetChannelMessages, GetChannelMessagesResponse), @@ -246,6 +246,7 @@ request_messages!( (RegisterProject, RegisterProjectResponse), (RegisterWorktree, Ack), (ReloadBuffers, ReloadBuffersResponse), + (RenameProjectEntry, ProjectEntryResponse), (SaveBuffer, BufferSaved), (SearchProject, SearchProjectResponse), (SendChannelMessage, SendChannelMessageResponse), diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index c77b10e1bd..d524735bac 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -502,6 +502,23 @@ impl SumTree { replaced } + pub fn remove(&mut self, key: &T::Key, cx: &::Context) -> Option { + let mut removed = None; + *self = { + let mut cursor = self.cursor::(); + let mut new_tree = cursor.slice(key, Bias::Left, cx); + if let Some(item) = cursor.item() { + if item.key() == *key { + removed = Some(item.clone()); + cursor.next(cx); + } + } + new_tree.push_tree(cursor.suffix(cx), cx); + new_tree + }; + removed + } + pub fn edit( &mut self, mut edits: Vec>,