Allow guests to rename stuff

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2022-05-04 10:27:04 -07:00
parent 470d693d5e
commit 438e4e7a19
7 changed files with 113 additions and 29 deletions

View file

@ -127,6 +127,7 @@ impl Server {
.add_request_handler(Server::forward_project_request::<proto::ReloadBuffers>) .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::FormatBuffers>)
.add_request_handler(Server::forward_project_request::<proto::CreateProjectEntry>) .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_request_handler(Server::update_buffer)
.add_message_handler(Server::update_buffer_file) .add_message_handler(Server::update_buffer_file)
.add_message_handler(Server::buffer_reloaded) .add_message_handler(Server::buffer_reloaded)
@ -1810,7 +1811,7 @@ mod tests {
} }
#[gpui::test(iterations = 10)] #[gpui::test(iterations = 10)]
async fn test_worktree_manipulation( async fn test_fs_operations(
executor: Arc<Deterministic>, executor: Arc<Deterministic>,
cx_a: &mut TestAppContext, cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext, cx_b: &mut TestAppContext,
@ -1848,14 +1849,12 @@ mod tests {
let worktree_b = let worktree_b =
project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap()); project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
project_b let entry = project_b
.update(cx_b, |project, cx| { .update(cx_b, |project, cx| {
project.create_file((worktree_id, "c.txt"), cx).unwrap() project.create_file((worktree_id, "c.txt"), cx).unwrap()
}) })
.await .await
.unwrap(); .unwrap();
executor.run_until_parked();
worktree_a.read_with(cx_a, |worktree, _| { worktree_a.read_with(cx_a, |worktree, _| {
assert_eq!( assert_eq!(
worktree worktree
@ -1874,6 +1873,32 @@ mod tests {
[".zed.toml", "a.txt", "b.txt", "c.txt"] [".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)] #[gpui::test(iterations = 10)]

View file

@ -262,6 +262,7 @@ impl Project {
client.add_model_message_handler(Self::handle_update_diagnostic_summary); client.add_model_message_handler(Self::handle_update_diagnostic_summary);
client.add_model_message_handler(Self::handle_update_worktree); 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_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_additional_edits_for_completion);
client.add_model_request_handler(Self::handle_apply_code_action); client.add_model_request_handler(Self::handle_apply_code_action);
client.add_model_request_handler(Self::handle_reload_buffers); client.add_model_request_handler(Self::handle_reload_buffers);
@ -736,9 +737,9 @@ impl Project {
new_path: impl Into<Arc<Path>>, new_path: impl Into<Arc<Path>>,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Option<Task<Result<Entry>>> { ) -> Option<Task<Result<Entry>>> {
let worktree = self.worktree_for_entry(entry_id, cx)?;
let new_path = new_path.into();
if self.is_local() { if self.is_local() {
let worktree = self.worktree_for_entry(entry_id, cx)?;
worktree.update(cx, |worktree, cx| { worktree.update(cx, |worktree, cx| {
worktree worktree
.as_local_mut() .as_local_mut()
@ -746,7 +747,27 @@ impl Project {
.rename_entry(entry_id, new_path, cx) .rename_entry(entry_id, new_path, cx)
}) })
} else { } 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>, envelope: TypedEnvelope<proto::CreateProjectEntry>,
_: Arc<Client>, _: Arc<Client>,
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<proto::CreateProjectEntryResponse> { ) -> Result<proto::ProjectEntryResponse> {
let entry = this let entry = this
.update(&mut cx, |this, cx| { .update(&mut cx, |this, cx| {
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
@ -3820,7 +3841,26 @@ impl Project {
}) })
})? })?
.await?; .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()), entry: Some((&entry).into()),
}) })
} }

View file

@ -956,6 +956,14 @@ impl Snapshot {
self.entries_by_id.get(&entry_id, &()).is_some() 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> { pub(crate) fn insert_entry(&mut self, entry: proto::Entry) -> Result<Entry> {
let entry = Entry::try_from((&self.root_char_bag, entry))?; let entry = Entry::try_from((&self.root_char_bag, entry))?;
self.entries_by_id.insert_or_replace( self.entries_by_id.insert_or_replace(

View file

@ -295,11 +295,6 @@ impl ProjectPanel {
Ok(()) Ok(())
})) }))
} else { } else {
// TODO - implement this for remote projects
if !worktree.read(cx).is_local() {
return None;
}
let old_path = entry.path.clone(); let old_path = entry.path.clone();
let new_path = if let Some(parent) = old_path.parent() { let new_path = if let Some(parent) = old_path.parent() {
parent.join(filename) parent.join(filename)

View file

@ -38,9 +38,9 @@ message Envelope {
UpdateWorktree update_worktree = 31; UpdateWorktree update_worktree = 31;
CreateProjectEntry create_project_entry = 32; CreateProjectEntry create_project_entry = 32;
CreateProjectEntryResponse create_project_entry_response = 33; RenameProjectEntry rename_project_entry = 33;
RenameProjectEntry rename_project_entry = 34; DeleteProjectEntry delete_project_entry = 34;
DeleteProjectEntry delete_project_entry = 35; ProjectEntryResponse project_entry_response = 35;
UpdateDiagnosticSummary update_diagnostic_summary = 36; UpdateDiagnosticSummary update_diagnostic_summary = 36;
StartLanguageServer start_language_server = 37; StartLanguageServer start_language_server = 37;
@ -171,16 +171,10 @@ message CreateProjectEntry {
bool is_directory = 4; bool is_directory = 4;
} }
message CreateProjectEntryResponse {
Entry entry = 1;
}
message RenameProjectEntry { message RenameProjectEntry {
uint64 project_id = 1; uint64 project_id = 1;
uint64 old_worktree_id = 2; uint64 entry_id = 2;
string old_path = 3; bytes new_path = 3;
uint64 new_worktree_id = 4;
string new_path = 5;
} }
message DeleteProjectEntry { message DeleteProjectEntry {
@ -189,6 +183,10 @@ message DeleteProjectEntry {
string path = 3; string path = 3;
} }
message ProjectEntryResponse {
Entry entry = 1;
}
message AddProjectCollaborator { message AddProjectCollaborator {
uint64 project_id = 1; uint64 project_id = 1;
Collaborator collaborator = 2; Collaborator collaborator = 2;

View file

@ -148,7 +148,6 @@ messages!(
(BufferSaved, Foreground), (BufferSaved, Foreground),
(ChannelMessageSent, Foreground), (ChannelMessageSent, Foreground),
(CreateProjectEntry, Foreground), (CreateProjectEntry, Foreground),
(CreateProjectEntryResponse, Foreground),
(DeleteProjectEntry, Foreground), (DeleteProjectEntry, Foreground),
(Error, Foreground), (Error, Foreground),
(Follow, Foreground), (Follow, Foreground),
@ -177,8 +176,6 @@ messages!(
(JoinChannelResponse, Foreground), (JoinChannelResponse, Foreground),
(JoinProject, Foreground), (JoinProject, Foreground),
(JoinProjectResponse, Foreground), (JoinProjectResponse, Foreground),
(StartLanguageServer, Foreground),
(UpdateLanguageServer, Foreground),
(LeaveChannel, Foreground), (LeaveChannel, Foreground),
(LeaveProject, Foreground), (LeaveProject, Foreground),
(OpenBufferById, Background), (OpenBufferById, Background),
@ -190,6 +187,7 @@ messages!(
(PerformRenameResponse, Background), (PerformRenameResponse, Background),
(PrepareRename, Background), (PrepareRename, Background),
(PrepareRenameResponse, Background), (PrepareRenameResponse, Background),
(ProjectEntryResponse, Foreground),
(RegisterProjectResponse, Foreground), (RegisterProjectResponse, Foreground),
(Ping, Foreground), (Ping, Foreground),
(RegisterProject, Foreground), (RegisterProject, Foreground),
@ -204,6 +202,7 @@ messages!(
(SendChannelMessage, Foreground), (SendChannelMessage, Foreground),
(SendChannelMessageResponse, Foreground), (SendChannelMessageResponse, Foreground),
(ShareProject, Foreground), (ShareProject, Foreground),
(StartLanguageServer, Foreground),
(Test, Foreground), (Test, Foreground),
(Unfollow, Foreground), (Unfollow, Foreground),
(UnregisterProject, Foreground), (UnregisterProject, Foreground),
@ -214,6 +213,7 @@ messages!(
(UpdateContacts, Foreground), (UpdateContacts, Foreground),
(UpdateDiagnosticSummary, Foreground), (UpdateDiagnosticSummary, Foreground),
(UpdateFollowers, Foreground), (UpdateFollowers, Foreground),
(UpdateLanguageServer, Foreground),
(UpdateWorktree, Foreground), (UpdateWorktree, Foreground),
); );
@ -223,7 +223,7 @@ request_messages!(
ApplyCompletionAdditionalEdits, ApplyCompletionAdditionalEdits,
ApplyCompletionAdditionalEditsResponse ApplyCompletionAdditionalEditsResponse
), ),
(CreateProjectEntry, CreateProjectEntryResponse), (CreateProjectEntry, ProjectEntryResponse),
(Follow, FollowResponse), (Follow, FollowResponse),
(FormatBuffers, FormatBuffersResponse), (FormatBuffers, FormatBuffersResponse),
(GetChannelMessages, GetChannelMessagesResponse), (GetChannelMessages, GetChannelMessagesResponse),
@ -246,6 +246,7 @@ request_messages!(
(RegisterProject, RegisterProjectResponse), (RegisterProject, RegisterProjectResponse),
(RegisterWorktree, Ack), (RegisterWorktree, Ack),
(ReloadBuffers, ReloadBuffersResponse), (ReloadBuffers, ReloadBuffersResponse),
(RenameProjectEntry, ProjectEntryResponse),
(SaveBuffer, BufferSaved), (SaveBuffer, BufferSaved),
(SearchProject, SearchProjectResponse), (SearchProject, SearchProjectResponse),
(SendChannelMessage, SendChannelMessageResponse), (SendChannelMessage, SendChannelMessageResponse),

View file

@ -502,6 +502,23 @@ impl<T: KeyedItem> SumTree<T> {
replaced 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( pub fn edit(
&mut self, &mut self,
mut edits: Vec<Edit<T>>, mut edits: Vec<Edit<T>>,