From 333b4aaf4e49ebd5a47f2247ba6e4bae1bfd00a6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 29 Apr 2022 17:17:04 -0700 Subject: [PATCH] Implement Rename command in project panel --- crates/project/src/worktree.rs | 32 ++++++ crates/project_panel/Cargo.toml | 2 +- crates/project_panel/src/project_panel.rs | 132 ++++++++++++++++++++-- 3 files changed, 154 insertions(+), 12 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index b7a075395b..812783aaaf 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -694,6 +694,38 @@ impl LocalWorktree { }) } + pub fn rename( + &self, + old_path: impl Into>, + new_path: impl Into>, + cx: &mut ModelContext, + ) -> Task> { + let old_path = old_path.into(); + let new_path = new_path.into(); + let abs_old_path = self.absolutize(&old_path); + let abs_new_path = self.absolutize(&new_path); + let background_snapshot = self.background_snapshot.clone(); + let fs = self.fs.clone(); + let rename = cx.background().spawn(async move { + fs.rename(&abs_old_path, &abs_new_path, Default::default()) + .await?; + background_snapshot.lock().remove_path(&old_path); + refresh_entry( + fs.as_ref(), + &background_snapshot, + new_path.clone(), + &abs_new_path, + ) + .await + }); + + cx.spawn(|this, mut cx| async move { + let entry = rename.await?; + this.update(&mut cx, |this, cx| this.poll_snapshot(cx)); + Ok(entry) + }) + } + pub fn register( &mut self, project_id: u64, diff --git a/crates/project_panel/Cargo.toml b/crates/project_panel/Cargo.toml index caedaef8b1..4b78f2a1fa 100644 --- a/crates/project_panel/Cargo.toml +++ b/crates/project_panel/Cargo.toml @@ -18,7 +18,7 @@ workspace = { path = "../workspace" } unicase = "2.6" [dev-dependencies] -editor = { path = "../editor", feature = ["test-support"] } +editor = { path = "../editor", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } workspace = { path = "../workspace", features = ["test-support"] } serde_json = { version = "1.0.64", features = ["preserve_order"] } diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index a28fc5e46e..37f14d7962 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -74,7 +74,7 @@ pub struct Open(pub ProjectEntryId); actions!( project_panel, - [ExpandSelectedEntry, CollapseSelectedEntry, AddFile] + [ExpandSelectedEntry, CollapseSelectedEntry, AddFile, Rename] ); impl_internal_actions!(project_panel, [Open, ToggleExpanded]); @@ -86,6 +86,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(ProjectPanel::select_next); cx.add_action(ProjectPanel::open_entry); cx.add_action(ProjectPanel::add_file); + cx.add_action(ProjectPanel::rename); cx.add_async_action(ProjectPanel::confirm); cx.add_action(ProjectPanel::cancel); } @@ -298,8 +299,23 @@ impl ProjectPanel { Ok(()) })) } else { - // TODO - implement - None + let old_path = entry.path.clone(); + let new_path = if let Some(parent) = old_path.parent() { + parent.join(filename) + } else { + filename.into() + }; + let rename = worktree.update(cx, |worktree, cx| { + worktree.as_local().unwrap().rename(old_path, new_path, cx) + }); + Some(cx.spawn(|this, mut cx| async move { + let new_entry = rename.await?; + this.update(&mut cx, |this, cx| { + this.update_visible_entries(Some((edit_state.worktree_id, new_entry.id)), cx); + cx.notify(); + }); + Ok(()) + })) } } @@ -362,8 +378,35 @@ impl ProjectPanel { .update(cx, |editor, cx| editor.clear(cx)); cx.focus(&self.filename_editor); self.update_visible_entries(None, cx); + cx.notify(); + } + } + + fn rename(&mut self, _: &Rename, cx: &mut ViewContext) { + if let Some(Selection { + worktree_id, + entry_id, + }) = self.selection + { + if let Some(worktree) = self.project.read(cx).worktree_for_id(worktree_id, cx) { + if let Some(entry) = worktree.read(cx).entry_for_id(entry_id) { + self.edit_state = Some(EditState { + worktree_id, + entry_id, + new_file: false, + }); + let filename = entry + .path + .file_name() + .map_or(String::new(), |s| s.to_string_lossy().to_string()); + self.filename_editor + .update(cx, |editor, cx| editor.set_text(filename, cx)); + cx.focus(&self.filename_editor); + self.update_visible_entries(None, cx); + cx.notify(); + } + } } - cx.notify(); } fn editor_blurred(&mut self, cx: &mut ViewContext) { @@ -1074,13 +1117,15 @@ mod tests { ] ); - panel.update(cx, |panel, cx| { - panel.filename_editor.update(cx, |editor, cx| { - editor.set_text("the-new-filename", cx); - }); - panel.confirm(&Confirm, cx); - }); - cx.foreground().run_until_parked(); + panel + .update(cx, |panel, cx| { + panel + .filename_editor + .update(cx, |editor, cx| editor.set_text("the-new-filename", cx)); + panel.confirm(&Confirm, cx).unwrap() + }) + .await + .unwrap(); assert_eq!( visible_entries_as_strings(&panel, 0..10, cx), &[ @@ -1112,6 +1157,71 @@ mod tests { " the-new-filename", ] ); + + panel + .update(cx, |panel, cx| { + panel + .filename_editor + .update(cx, |editor, cx| editor.set_text("another-filename", cx)); + panel.confirm(&Confirm, cx).unwrap() + }) + .await + .unwrap(); + assert_eq!( + visible_entries_as_strings(&panel, 0..9, cx), + &[ + "v root1", + " > a", + " v b <== selected", + " > 3", + " > 4", + " another-filename", + " > C", + " .dockerignore", + " the-new-filename", + ] + ); + + select_path(&panel, "root1/b/another-filename", cx); + panel.update(cx, |panel, cx| panel.rename(&Rename, cx)); + assert_eq!( + visible_entries_as_strings(&panel, 0..9, cx), + &[ + "v root1", + " > a", + " v b", + " > 3", + " > 4", + " [RENAME EDITOR] <== selected", + " > C", + " .dockerignore", + " the-new-filename", + ] + ); + + panel + .update(cx, |panel, cx| { + panel + .filename_editor + .update(cx, |editor, cx| editor.set_text("a-different-filename", cx)); + panel.confirm(&Confirm, cx).unwrap() + }) + .await + .unwrap(); + assert_eq!( + visible_entries_as_strings(&panel, 0..9, cx), + &[ + "v root1", + " > a", + " v b", + " > 3", + " > 4", + " a-different-filename <== selected", + " > C", + " .dockerignore", + " the-new-filename", + ] + ); } fn toggle_expand_dir(