Detailed changes
@@ -127,6 +127,7 @@ impl Server {
.add_request_handler(Server::forward_project_request::<proto::ReloadBuffers>)
.add_request_handler(Server::forward_project_request::<proto::FormatBuffers>)
.add_request_handler(Server::forward_project_request::<proto::CreateProjectEntry>)
+ .add_request_handler(Server::forward_project_request::<proto::RenameProjectEntry>)
.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<Deterministic>,
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::<Vec<_>>(),
+ [".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::<Vec<_>>(),
+ [".zed.toml", "a.txt", "b.txt", "d.txt"]
+ );
+ });
}
#[gpui::test(iterations = 10)]
@@ -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<Arc<Path>>,
cx: &mut ModelContext<Self>,
) -> Option<Task<Result<Entry>>> {
+ 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<proto::CreateProjectEntry>,
_: Arc<Client>,
mut cx: AsyncAppContext,
- ) -> Result<proto::CreateProjectEntryResponse> {
+ ) -> Result<proto::ProjectEntryResponse> {
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<Self>,
+ envelope: TypedEnvelope<proto::RenameProjectEntry>,
+ _: Arc<Client>,
+ mut cx: AsyncAppContext,
+ ) -> Result<proto::ProjectEntryResponse> {
+ 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()),
})
}
@@ -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<Entry> {
+ 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<Entry> {
let entry = Entry::try_from((&self.root_char_bag, entry))?;
self.entries_by_id.insert_or_replace(
@@ -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)
@@ -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;
@@ -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),
@@ -502,6 +502,23 @@ impl<T: KeyedItem> SumTree<T> {
replaced
}
+ pub fn remove(&mut self, key: &T::Key, cx: &<T::Summary as Summary>::Context) -> Option<T> {
+ let mut removed = None;
+ *self = {
+ let mut cursor = self.cursor::<T::Key>();
+ 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<Edit<T>>,