project_panel: Collapse top-level entries in Collapse all entries command (#38310)
Closes #11760 The command `project panel: collapse all entries` currently does not collapse top-level entries (the workspaces themselves). I think this should be expected behaviour if you only have a single workspace in your project. However, if you have multiple workspaces, we should collapse their top-level folders as well. This is the expected behaviour in the screenshots in #11760. For more context: Atm the `.retain` function empties the `self.expanded_dir_ids` Hash Map, because the `expanded_entries` Vec is (almost) never empty - it contains the id of the `root_entry` of the workspace. https://github.com/zed-industries/zed/blob/d48d6a745409a8998998ed59c28493a1aa733ebb/crates/project_panel/src/project_panel.rs#L1148-L1152 We then update the `self.expanded_dir_ids` in the `update_visible_entries` function, and since the Hash Map is empty, we execute the `hash_map::Entry::Vacant` arm of the following match statement. https://github.com/zed-industries/zed/blob/d48d6a745409a8998998ed59c28493a1aa733ebb/crates/project_panel/src/project_panel.rs#L3062-L3073 This change makes sure that we do not clear the `expanded_dir_ids` HashMap and always keep the keys for all visible workspaces and therefore we run the `hash_map::Entry::Occupied` arm, which does not override the `expanded_dir_ids` anymore. https://github.com/user-attachments/assets/b607523b-2ea2-4159-8edf-aed7bca05e3a cc @MrSubidubi Release Notes: - N/A *or* Added/Fixed/Improved ... --------- Co-authored-by: Finn Evers <finn.evers@outlook.de>
This commit is contained in:
@@ -1147,8 +1147,32 @@ impl ProjectPanel {
|
||||
) {
|
||||
// By keeping entries for fully collapsed worktrees, we avoid expanding them within update_visible_entries
|
||||
// (which is it's default behavior when there's no entry for a worktree in expanded_dir_ids).
|
||||
let multiple_worktrees = self.project.read(cx).worktrees(cx).count() > 1;
|
||||
let project = self.project.read(cx);
|
||||
|
||||
self.expanded_dir_ids
|
||||
.retain(|_, expanded_entries| expanded_entries.is_empty());
|
||||
.iter_mut()
|
||||
.for_each(|(worktree_id, expanded_entries)| {
|
||||
if multiple_worktrees {
|
||||
*expanded_entries = Default::default();
|
||||
return;
|
||||
}
|
||||
|
||||
let root_entry_id = project
|
||||
.worktree_for_id(*worktree_id, cx)
|
||||
.map(|worktree| worktree.read(cx).snapshot())
|
||||
.and_then(|worktree_snapshot| {
|
||||
worktree_snapshot.root_entry().map(|entry| entry.id)
|
||||
});
|
||||
|
||||
match root_entry_id {
|
||||
Some(id) => {
|
||||
expanded_entries.retain(|entry_id| entry_id == &id);
|
||||
}
|
||||
None => *expanded_entries = Default::default(),
|
||||
};
|
||||
});
|
||||
|
||||
self.update_visible_entries(None, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
@@ -2747,6 +2747,111 @@ async fn test_collapse_all_entries(cx: &mut gpui::TestAppContext) {
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_collapse_all_entries_multiple_worktrees(cx: &mut gpui::TestAppContext) {
|
||||
init_test_with_editor(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let worktree_content = json!({
|
||||
"dir_1": {
|
||||
"file_1.py": "# File contents",
|
||||
},
|
||||
"dir_2": {
|
||||
"file_1.py": "# File contents",
|
||||
}
|
||||
});
|
||||
|
||||
fs.insert_tree("/project_root_1", worktree_content.clone())
|
||||
.await;
|
||||
fs.insert_tree("/project_root_2", worktree_content).await;
|
||||
|
||||
let project = Project::test(
|
||||
fs.clone(),
|
||||
["/project_root_1".as_ref(), "/project_root_2".as_ref()],
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
let panel = workspace.update(cx, ProjectPanel::new).unwrap();
|
||||
|
||||
panel.update_in(cx, |panel, window, cx| {
|
||||
panel.collapse_all_entries(&CollapseAllEntries, window, cx)
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
assert_eq!(
|
||||
visible_entries_as_strings(&panel, 0..10, cx),
|
||||
&["> project_root_1", "> project_root_2",]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_collapse_all_entries_with_collapsed_root(cx: &mut gpui::TestAppContext) {
|
||||
init_test_with_editor(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
"/project_root",
|
||||
json!({
|
||||
"dir_1": {
|
||||
"nested_dir": {
|
||||
"file_a.py": "# File contents",
|
||||
"file_b.py": "# File contents",
|
||||
"file_c.py": "# File contents",
|
||||
},
|
||||
"file_1.py": "# File contents",
|
||||
"file_2.py": "# File contents",
|
||||
"file_3.py": "# File contents",
|
||||
},
|
||||
"dir_2": {
|
||||
"file_1.py": "# File contents",
|
||||
"file_2.py": "# File contents",
|
||||
"file_3.py": "# File contents",
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), ["/project_root".as_ref()], cx).await;
|
||||
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
let panel = workspace.update(cx, ProjectPanel::new).unwrap();
|
||||
|
||||
// Open project_root/dir_1 to ensure that a nested directory is expanded
|
||||
toggle_expand_dir(&panel, "project_root/dir_1", cx);
|
||||
cx.executor().run_until_parked();
|
||||
assert_eq!(
|
||||
visible_entries_as_strings(&panel, 0..10, cx),
|
||||
&[
|
||||
"v project_root",
|
||||
" v dir_1 <== selected",
|
||||
" > nested_dir",
|
||||
" file_1.py",
|
||||
" file_2.py",
|
||||
" file_3.py",
|
||||
" > dir_2",
|
||||
]
|
||||
);
|
||||
|
||||
// Close root directory
|
||||
toggle_expand_dir(&panel, "project_root", cx);
|
||||
cx.executor().run_until_parked();
|
||||
assert_eq!(
|
||||
visible_entries_as_strings(&panel, 0..10, cx),
|
||||
&["> project_root <== selected"]
|
||||
);
|
||||
|
||||
// Run collapse_all_entries and make sure root is not expanded
|
||||
panel.update_in(cx, |panel, window, cx| {
|
||||
panel.collapse_all_entries(&CollapseAllEntries, window, cx)
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
assert_eq!(
|
||||
visible_entries_as_strings(&panel, 0..10, cx),
|
||||
&["> project_root <== selected"]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_new_file_move(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
Reference in New Issue
Block a user