diff --git a/assets/settings/default.json b/assets/settings/default.json index 3cc556b9f11bec..ea2e6ff99ef4b6 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -187,10 +187,7 @@ // Whether to reveal it in the project panel automatically, // when a corresponding project entry becomes active. // Gitignored entries are never auto revealed. - "auto_reveal_entries": true, - /// Whether to fold directories automatically - /// when directory has only one directory inside. - "auto_fold_dirs": true + "auto_reveal_entries": true }, "collaboration_panel": { // Whether to show the collaboration panel button in the status bar. diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 413d422557f2af..3744a36c00f61e 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -19,18 +19,11 @@ use gpui::{ use menu::{Confirm, SelectNext, SelectPrev}; use project::{ repository::GitFileStatus, Entry, EntryKind, Fs, Project, ProjectEntryId, ProjectPath, - Snapshot, Worktree, WorktreeId, + Worktree, WorktreeId, }; use project_panel_settings::{ProjectPanelDockPosition, ProjectPanelSettings}; use serde::{Deserialize, Serialize}; -use std::{ - cmp::Ordering, - collections::HashSet, - ffi::OsStr, - ops::Range, - path::{Path, PathBuf}, - sync::Arc, -}; +use std::{cmp::Ordering, ffi::OsStr, ops::Range, path::Path, sync::Arc}; use theme::ThemeSettings; use ui::{prelude::*, v_flex, ContextMenu, Icon, KeyBinding, Label, ListItem}; use unicase::UniCase; @@ -52,7 +45,6 @@ pub struct ProjectPanel { visible_entries: Vec<(WorktreeId, Vec)>, last_worktree_root_id: Option, expanded_dir_ids: HashMap>, - unfolded_dir_ids: HashSet, selection: Option, context_menu: Option<(View, Point, Subscription)>, edit_state: Option, @@ -128,8 +120,6 @@ actions!( Open, ToggleFocus, NewSearchInDirectory, - UnfoldDirectory, - FoldDirectory, ] ); @@ -241,7 +231,6 @@ impl ProjectPanel { visible_entries: Default::default(), last_worktree_root_id: Default::default(), expanded_dir_ids: Default::default(), - unfolded_dir_ids: Default::default(), selection: None, edit_state: None, context_menu: None, @@ -400,11 +389,8 @@ impl ProjectPanel { }); if let Some((worktree, entry)) = self.selected_entry(cx) { - let auto_fold_dirs = ProjectPanelSettings::get_global(cx).auto_fold_dirs; let is_root = Some(entry) == worktree.root_entry(); let is_dir = entry.is_dir(); - let is_foldable = self.is_foldable(entry, worktree) && auto_fold_dirs; - let is_unfoldable = self.is_unfoldable(entry, worktree) && auto_fold_dirs; let worktree_id = worktree.id(); let is_local = project.is_local(); let is_read_only = project.is_read_only(); @@ -455,12 +441,6 @@ impl ProjectPanel { menu.action("Open in Terminal", Box::new(OpenInTerminal)) .action("Search Inside", Box::new(NewSearchInDirectory)) }) - .when(is_unfoldable, |menu| { - menu.action("Unfold Directory", Box::new(UnfoldDirectory)) - }) - .when(is_foldable, |menu| { - menu.action("Fold Directory", Box::new(FoldDirectory)) - }) .separator() .action("Rename", Box::new(Rename)) .when(!is_root, |menu| menu.action("Delete", Box::new(Delete))) @@ -479,35 +459,6 @@ impl ProjectPanel { cx.notify(); } - fn is_unfoldable(&self, entry: &Entry, worktree: &Worktree) -> bool { - if !entry.is_dir() || self.unfolded_dir_ids.contains(&entry.id) { - return false; - } - - if let Some(parent_path) = entry.path.parent() { - let children_count = worktree - .entries(false) - .filter(|e| e.path.parent() == Some(parent_path)) - .count(); - - return children_count <= 1; - }; - false - } - - fn is_foldable(&self, entry: &Entry, worktree: &Worktree) -> bool { - if !entry.is_dir() { - return false; - } - - let children_count: Vec<&Entry> = worktree // children count for unfolded dirs - .entries(true) - .filter(|e| e.path.parent() == Some(&entry.path)) - .collect(); - - children_count.len() <= 1 && (children_count.is_empty() || children_count[0].is_dir()) - } - fn expand_selected_entry(&mut self, _: &ExpandSelectedEntry, cx: &mut ViewContext) { if let Some((worktree, entry)) = self.selected_entry(cx) { if entry.is_dir() { @@ -866,53 +817,6 @@ impl ProjectPanel { }); } - fn unfold_directory(&mut self, _: &UnfoldDirectory, cx: &mut ViewContext) { - if let Some((worktree, entry)) = self.selected_entry(cx) { - self.unfolded_dir_ids.insert(entry.id); - - let mut parent_path = entry.path.parent(); - while let Some(path) = parent_path { - if let Some(parent_entry) = worktree.entry_for_path(path) { - let children_count = worktree - .entries(true) - .filter(|e| e.path.parent() == Some(path)) - .count(); - - if children_count > 1 { - break; - } - - self.unfolded_dir_ids.insert(parent_entry.id); - parent_path = path.parent(); - } else { - break; - } - } - - self.update_visible_entries(None, cx); - self.autoscroll(cx); - cx.notify(); - } - } - - fn fold_directory(&mut self, _: &FoldDirectory, cx: &mut ViewContext) { - if let Some((worktree, entry)) = self.selected_entry(cx) { - self.unfolded_dir_ids.remove(&entry.id); - - let children = worktree - .entries(true) - .filter(|e| e.path.starts_with(&entry.path) && e.path != entry.path); - - for child in children { - self.unfolded_dir_ids.remove(&child.id); - } - - self.update_visible_entries(None, cx); - self.autoscroll(cx); - cx.notify(); - } - } - fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext) { if let Some(selection) = self.selection { let (mut worktree_ix, mut entry_ix, _) = @@ -1196,7 +1100,6 @@ impl ProjectPanel { new_selected_entry: Option<(WorktreeId, ProjectEntryId)>, cx: &mut ViewContext, ) { - let auto_collapse_dirs = ProjectPanelSettings::get_global(cx).auto_fold_dirs; let project = self.project.read(cx); self.last_worktree_root_id = project .visible_worktrees(cx) @@ -1238,19 +1141,8 @@ impl ProjectPanel { let mut visible_worktree_entries = Vec::new(); let mut entry_iter = snapshot.entries(true); - while let Some(entry) = entry_iter.entry() { - if auto_collapse_dirs - && entry.kind.is_dir() - && !self.unfolded_dir_ids.contains(&entry.id) - { - let is_omitted = ProjectPanel::should_omit_entry(snapshot.clone(), entry); - - if is_omitted { - entry_iter.advance(); - continue; - } - } + while let Some(entry) = entry_iter.entry() { visible_worktree_entries.push(entry.clone()); if Some(entry.id) == new_entry_parent_id { visible_worktree_entries.push(Entry { @@ -1313,22 +1205,6 @@ impl ProjectPanel { } } - fn should_omit_entry(snapshot: Snapshot, entry: &Entry) -> bool { - if let Some(root_path) = snapshot.root_entry() { - if entry.path == root_path.path { - return false; - } - } - - let children: Vec<&Entry> = snapshot - .entries(true) - .into_iter() - .filter(|e| e.path.parent() == Some(&entry.path)) - .collect(); - - children.len() == 1 && children[0].kind.is_dir() - } - fn expand_entry( &mut self, worktree_id: WorktreeId, @@ -1418,32 +1294,16 @@ impl ProjectPanel { } }; - let (depth, difference) = ProjectPanel::calculate_depth_and_difference( - entry, - visible_worktree_entries, - ); - - let filename = match difference { - diff if diff > 1 => entry - .path - .iter() - .skip(entry.path.components().count() - diff) - .collect::() - .to_str() - .unwrap_or_default() - .to_string(), - _ => entry + let mut details = EntryDetails { + filename: entry .path .file_name() - .map(|name| name.to_string_lossy().into_owned()) - .unwrap_or_else(|| root_name.to_string_lossy().to_string()), - }; - - let mut details = EntryDetails { - filename, + .unwrap_or(root_name) + .to_string_lossy() + .to_string(), icon, path: entry.path.clone(), - depth, + depth: entry.path.components().count(), kind: entry.kind, is_ignored: entry.is_ignored, is_expanded, @@ -1487,40 +1347,6 @@ impl ProjectPanel { } } - fn calculate_depth_and_difference( - entry: &Entry, - visible_worktree_entries: &Vec, - ) -> (usize, usize) { - let entry_path_components_count = entry.path.components().count(); - let (depth, difference) = entry - .path - .ancestors() - .skip(1) // Skip the entry itself - .find_map(|ancestor| { - visible_worktree_entries - .iter() - .find(|&e| *e.path == *ancestor) - .map(|parent_entry| { - let parent_path_components_count = parent_entry.path.components().count(); - let difference = entry_path_components_count - parent_path_components_count; - let depth = parent_entry - .path - .ancestors() - .skip(1) - .filter(|ancestor| { - visible_worktree_entries - .iter() - .any(|e| *e.path == **ancestor) - }) - .count(); - (depth + 1, difference) - }) - }) - .unwrap_or((0, 0)); - - (depth, difference) - } - fn render_entry( &self, entry_id: ProjectEntryId, @@ -1677,8 +1503,6 @@ impl Render for ProjectPanel { .on_action(cx.listener(Self::copy_path)) .on_action(cx.listener(Self::copy_relative_path)) .on_action(cx.listener(Self::new_search_in_directory)) - .on_action(cx.listener(Self::unfold_directory)) - .on_action(cx.listener(Self::fold_directory)) .when(!project.is_read_only(), |el| { el.on_action(cx.listener(Self::new_file)) .on_action(cx.listener(Self::new_directory)) @@ -2029,7 +1853,7 @@ mod tests { &[ "v root1", " > a", - " > b/3", + " > b", " > C", " .dockerignore", "v root2", @@ -2038,14 +1862,14 @@ mod tests { ] ); - toggle_expand_dir(&panel, "root1/b/3", cx); + toggle_expand_dir(&panel, "root1/b", cx); assert_eq!( visible_entries_as_strings(&panel, 0..50, cx), &[ "v root1", " > a", - " v b/3 <== selected", - " Q", + " v b <== selected", + " > 3", " > C", " .dockerignore", "v root2", @@ -2060,8 +1884,8 @@ mod tests { &[ "v root1", " > a", - " v b/3", - " Q", + " v b", + " > 3", " > C", " .dockerignore", "v root2", @@ -2076,8 +1900,8 @@ mod tests { &[ "v root1", " > a", - " v b/3", - " Q", + " v b", + " > 3", " > C", " .dockerignore", "v root2", @@ -2087,115 +1911,6 @@ mod tests { ); } - #[gpui::test] - async fn test_auto_collapse_dir_paths(cx: &mut gpui::TestAppContext) { - init_test(cx); - - let fs = FakeFs::new(cx.executor().clone()); - fs.insert_tree( - "/root1", - json!({ - "dir_1": { - "nested_dir_1": { - "nested_dir_2": { - "nested_dir_3": { - "file_a.java": "// File contents", - "file_b.java": "// File contents", - "file_c.java": "// File contents", - "nested_dir_4": { - "nested_dir_5": { - "file_d.java": "// File contents", - } - } - } - } - } - } - }), - ) - .await; - fs.insert_tree( - "/root2", - json!({ - "dir_2": { - "file_1.java": "// File contents", - } - }), - ) - .await; - - let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".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(); - assert_eq!( - visible_entries_as_strings(&panel, 0..10, cx), - &[ - "v root1", - " > dir_1/nested_dir_1/nested_dir_2/nested_dir_3", - "v root2", - " > dir_2", - ] - ); - - toggle_expand_dir( - &panel, - "root1/dir_1/nested_dir_1/nested_dir_2/nested_dir_3", - cx, - ); - assert_eq!( - visible_entries_as_strings(&panel, 0..10, cx), - &[ - "v root1", - " v dir_1/nested_dir_1/nested_dir_2/nested_dir_3 <== selected", - " > nested_dir_4/nested_dir_5", - " file_a.java", - " file_b.java", - " file_c.java", - "v root2", - " > dir_2", - ] - ); - - toggle_expand_dir( - &panel, - "root1/dir_1/nested_dir_1/nested_dir_2/nested_dir_3/nested_dir_4/nested_dir_5", - cx, - ); - assert_eq!( - visible_entries_as_strings(&panel, 0..10, cx), - &[ - "v root1", - " v dir_1/nested_dir_1/nested_dir_2/nested_dir_3", - " v nested_dir_4/nested_dir_5 <== selected", - " file_d.java", - " file_a.java", - " file_b.java", - " file_c.java", - "v root2", - " > dir_2", - ] - ); - toggle_expand_dir(&panel, "root2/dir_2", cx); - assert_eq!( - visible_entries_as_strings(&panel, 0..10, cx), - &[ - "v root1", - " v dir_1/nested_dir_1/nested_dir_2/nested_dir_3", - " v nested_dir_4/nested_dir_5", - " file_d.java", - " file_a.java", - " file_b.java", - " file_c.java", - "v root2", - " v dir_2 <== selected", - " file_1.java", - ] - ); - } - #[gpui::test(iterations = 30)] async fn test_editing_files(cx: &mut gpui::TestAppContext) { init_test(cx); @@ -2674,8 +2389,9 @@ mod tests { " > .git", " > a", " > b", - " v bdir1/dir2", - " the-new-filename <== selected", + " v bdir1", + " v dir2", + " the-new-filename <== selected", " > C", " .dockerignore", "v root2", @@ -2809,6 +2525,7 @@ mod tests { "Directories inside pasted directory should have an entry" ); + toggle_expand_dir(&panel, "root/b", cx); toggle_expand_dir(&panel, "root/b/a", cx); toggle_expand_dir(&panel, "root/b/a/inner_dir", cx); @@ -2818,12 +2535,13 @@ mod tests { // "v root", " > a", - " v b/a", - " v inner_dir <== selected", - " four.txt", - " three.txt", - " one.txt", - " two.txt", + " v b", + " v a", + " v inner_dir <== selected", + " four.txt", + " three.txt", + " one.txt", + " two.txt", ] ); @@ -2840,12 +2558,13 @@ mod tests { " > a", " > a copy", " > a copy 1", - " v b/a", - " v inner_dir", - " four.txt", - " three.txt", - " one.txt", - " two.txt" + " v b", + " v a", + " v inner_dir", + " four.txt", + " three.txt", + " one.txt", + " two.txt" ] ); } @@ -3137,15 +2856,18 @@ mod tests { 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_a.py", + " v dir_1", + " > nested_dir <== selected", " file_1.py", ] ); diff --git a/crates/project_panel/src/project_panel_settings.rs b/crates/project_panel/src/project_panel_settings.rs index 275119d755142b..5285684891e2b2 100644 --- a/crates/project_panel/src/project_panel_settings.rs +++ b/crates/project_panel/src/project_panel_settings.rs @@ -20,7 +20,6 @@ pub struct ProjectPanelSettings { pub git_status: bool, pub indent_size: f32, pub auto_reveal_entries: bool, - pub auto_fold_dirs: bool, } #[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug)] @@ -55,11 +54,6 @@ pub struct ProjectPanelSettingsContent { /// /// Default: true pub auto_reveal_entries: Option, - /// Whether to fold directories automatically - /// when directory has only one directory inside. - /// - /// Default: true - pub auto_fold_dirs: Option, } impl Settings for ProjectPanelSettings {