Add ability to expand/collapse directories using the `project_panel::Open` action (#6914)

d1y created

#6910

I changed the `open_file` symbol to `open`, because this is more
consistent with the original intention

Release Notes:

- Added the ability to expand/collapse directories using the
`project_panel::Open` action.

Change summary

crates/project_panel/src/project_panel.rs | 54 +++++++++++++++++++++++-
1 file changed, 50 insertions(+), 4 deletions(-)

Detailed changes

crates/project_panel/src/project_panel.rs 🔗

@@ -561,10 +561,12 @@ impl ProjectPanel {
         }
     }
 
-    fn open_file(&mut self, _: &Open, cx: &mut ViewContext<Self>) {
+    fn open(&mut self, _: &Open, cx: &mut ViewContext<Self>) {
         if let Some((_, entry)) = self.selected_entry(cx) {
             if entry.is_file() {
                 self.open_entry(entry.id, true, cx);
+            } else {
+                self.toggle_expanded(entry.id, cx);
             }
         }
     }
@@ -1476,7 +1478,7 @@ impl Render for ProjectPanel {
                 .on_action(cx.listener(Self::expand_selected_entry))
                 .on_action(cx.listener(Self::collapse_selected_entry))
                 .on_action(cx.listener(Self::collapse_all_entries))
-                .on_action(cx.listener(Self::open_file))
+                .on_action(cx.listener(Self::open))
                 .on_action(cx.listener(Self::confirm))
                 .on_action(cx.listener(Self::cancel))
                 .on_action(cx.listener(Self::copy_path))
@@ -2576,7 +2578,7 @@ mod tests {
 
         toggle_expand_dir(&panel, "src/test", cx);
         select_path(&panel, "src/test/first.rs", cx);
-        panel.update(cx, |panel, cx| panel.open_file(&Open, cx));
+        panel.update(cx, |panel, cx| panel.open(&Open, cx));
         cx.executor().run_until_parked();
         assert_eq!(
             visible_entries_as_strings(&panel, 0..10, cx),
@@ -2604,7 +2606,7 @@ mod tests {
         ensure_no_open_items_and_panes(&workspace, cx);
 
         select_path(&panel, "src/test/second.rs", cx);
-        panel.update(cx, |panel, cx| panel.open_file(&Open, cx));
+        panel.update(cx, |panel, cx| panel.open(&Open, cx));
         cx.executor().run_until_parked();
         assert_eq!(
             visible_entries_as_strings(&panel, 0..10, cx),
@@ -2810,6 +2812,50 @@ mod tests {
         );
     }
 
+    #[gpui::test]
+    async fn test_dir_toggle_collapse(cx: &mut gpui::TestAppContext) {
+        init_test_with_editor(cx);
+
+        let fs = FakeFs::new(cx.executor().clone());
+        fs.insert_tree(
+            "/project_root",
+            json!({
+                "dir_1": {
+                    "nested_dir": {
+                        "file_a.py": "# File contents",
+                    }
+                },
+                "file_1.py": "# File contents",
+            }),
+        )
+        .await;
+
+        let project = Project::test(fs.clone(), ["/project_root".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| ProjectPanel::new(workspace, cx))
+            .unwrap();
+
+        panel.update(cx, |panel, cx| panel.open(&Open, cx));
+        cx.executor().run_until_parked();
+        select_path(&panel, "project_root/dir_1", cx);
+        panel.update(cx, |panel, cx| panel.open(&Open, cx));
+        select_path(&panel, "project_root/dir_1/nested_dir", cx);
+        panel.update(cx, |panel, cx| panel.open(&Open, cx));
+        panel.update(cx, |panel, cx| panel.open(&Open, cx));
+        cx.executor().run_until_parked();
+        assert_eq!(
+            visible_entries_as_strings(&panel, 0..10, cx),
+            &[
+                "v project_root",
+                "    v dir_1",
+                "        > nested_dir  <== selected",
+                "      file_1.py",
+            ]
+        );
+    }
+
     #[gpui::test]
     async fn test_collapse_all_entries(cx: &mut gpui::TestAppContext) {
         init_test_with_editor(cx);