Create a new directory when a new file ends with `/` (#12018)

Avinash Thakur created

Release Notes:

- Made project panel to create directories when renaming into paths ending with `/`

Change summary

crates/project_panel/src/project_panel.rs | 82 ++++++++++++++++++++++++
1 file changed, 81 insertions(+), 1 deletion(-)

Detailed changes

crates/project_panel/src/project_panel.rs 🔗

@@ -698,10 +698,12 @@ impl ProjectPanel {
 
         let worktree_id = edit_state.worktree_id;
         let is_new_entry = edit_state.is_new_entry;
+        let filename = self.filename_editor.read(cx).text(cx);
+        edit_state.is_dir = edit_state.is_dir
+            || (edit_state.is_new_entry && filename.ends_with(std::path::MAIN_SEPARATOR));
         let is_dir = edit_state.is_dir;
         let worktree = self.project.read(cx).worktree_for_id(worktree_id, cx)?;
         let entry = worktree.read(cx).entry_for_id(edit_state.entry_id)?.clone();
-        let filename = self.filename_editor.read(cx).text(cx);
 
         let path_already_exists = |path| worktree.read(cx).entry_for_path(path).is_some();
         let edit_task;
@@ -2903,6 +2905,84 @@ mod tests {
         );
     }
 
+    #[gpui::test]
+    async fn test_adding_directory_via_file(cx: &mut gpui::TestAppContext) {
+        init_test(cx);
+
+        let fs = FakeFs::new(cx.executor().clone());
+        fs.insert_tree(
+            "/root1",
+            json!({
+                ".dockerignore": "",
+                ".git": {
+                    "HEAD": "",
+                },
+            }),
+        )
+        .await;
+
+        let project = Project::test(fs.clone(), ["/root1".as_ref()], cx).await;
+        let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
+        let cx = &mut VisualTestContext::from_window(*workspace, cx);
+        let panel = workspace
+            .update(cx, |workspace, cx| {
+                let panel = ProjectPanel::new(workspace, cx);
+                workspace.add_panel(panel.clone(), cx);
+                panel
+            })
+            .unwrap();
+
+        select_path(&panel, "root1", cx);
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..10, cx),
+            &["v root1  <== selected", "    > .git", "      .dockerignore",]
+        );
+
+        // Add a file with the root folder selected. The filename editor is placed
+        // before the first file in the root folder.
+        panel.update(cx, |panel, cx| panel.new_file(&NewFile, cx));
+        panel.update(cx, |panel, cx| {
+            assert!(panel.filename_editor.read(cx).is_focused(cx));
+        });
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..10, cx),
+            &[
+                "v root1",
+                "    > .git",
+                "      [EDITOR: '']  <== selected",
+                "      .dockerignore",
+            ]
+        );
+
+        let confirm = panel.update(cx, |panel, cx| {
+            panel
+                .filename_editor
+                .update(cx, |editor, cx| editor.set_text("/new_dir/", cx));
+            panel.confirm_edit(cx).unwrap()
+        });
+
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..10, cx),
+            &[
+                "v root1",
+                "    > .git",
+                "      [PROCESSING: '/new_dir/']  <== selected",
+                "      .dockerignore",
+            ]
+        );
+
+        confirm.await.unwrap();
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..13, cx),
+            &[
+                "v root1",
+                "    > .git",
+                "    v new_dir  <== selected",
+                "      .dockerignore",
+            ]
+        );
+    }
+
     #[gpui::test]
     async fn test_copy_paste(cx: &mut gpui::TestAppContext) {
         init_test(cx);