Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of auto folded directories #7674

Merged
merged 10 commits into from
Feb 26, 2024

Conversation

ABckh
Copy link
Contributor

@ABckh ABckh commented Feb 11, 2024

Added support of auto collapsed directories, for example when directory has only one directory inside we should display it as dir1/dir2 (#6935 ). Please feel free to propose better solutions, as I am new in Rust

Demo:
https://streamable.com/seo3n9

Release Notes:

  • Added support for auto-collapsing directories.

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Feb 11, 2024
@maxbrunsfeld maxbrunsfeld self-assigned this Feb 12, 2024
Copy link
Collaborator

@maxbrunsfeld maxbrunsfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @ABckh . Thanks for adding tests and that demo video. I left some suggestions on the implementation.

@@ -120,6 +122,8 @@ actions!(
Open,
ToggleFocus,
NewSearchInDirectory,
UnfoldTheChildren,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call these commands "Fold/Unfold Directory" instead of "Fold/Unfold The Children".

@@ -45,6 +45,8 @@ pub struct ProjectPanel {
visible_entries: Vec<(WorktreeId, Vec<Entry>)>,
last_worktree_root_id: Option<ProjectEntryId>,
expanded_dir_ids: HashMap<WorktreeId, Vec<ProjectEntryId>>,
collapsed_dir_paths: HashMap<ProjectEntryId, String>,
excluded_collapsed_dir_paths: HashMap<ProjectEntryId, String>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should only add a single piece of state here: unfolded_dir_ids - which are the set of directories that have been explicitly unfolded. It could be structured similarly to expanded_dir_ids (in a hash map keyed by WorktreeId, or perhaps a simple HashSet<ProjectEntryId>.

I think we can remove the String (for the folded paths). I'll explain more below.

while let Some(entry) = entry_iter.entry() {
visible_worktree_entries.push(entry.clone());
if auto_collapse_dirs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than storing the folded paths explicitly as strings, I think we could use the existing path field that's on an Entry, and if we noticed that the entrie's descendant directories should be folded, we can render multiple components of the path (instead of just the filename).

So in this loop, could we simply omit entries for directories that are folded, so that the visible_worktree_entries vector would look like this:

[
    Entry {
        path: "src",
        // ...
    },
    // The entries for the singleton directories `dir1` and `dir2` are omitted,
    // because we decided to fold those single-child directories.
    Entry {
        path: "src/dir1/dir2/TheFile.java",
        // ...
    },
]

Then, when processing these entries in for_each_visible_entry, we could notice that the entry for TheFile.java has some folded descendants, because its path differs from its predecessor's path by more than one path component. When we detect that, we could render all of the additional path components (dir1/dir2/TheFile.java), not just the filename (TheFile.java).

With this approach, we don't need to store as much redundant state. Does that make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does, this approach looks better. I will try to implement it, thank you!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than storing the folded paths explicitly as strings, I think we could use the existing path field that's on an Entry, and if we noticed that the entrie's descendant directories should be folded, we can render multiple components of the path (instead of just the filename).

So in this loop, could we simply omit entries for directories that are folded, so that the visible_worktree_entries vector would look like this:

[
    Entry {
        path: "src",
        // ...
    },
    // The entries for the singleton directories `dir1` and `dir2` are omitted,
    // because we decided to fold those single-child directories.
    Entry {
        path: "src/dir1/dir2/TheFile.java",
        // ...
    },
]

Then, when processing these entries in for_each_visible_entry, we could notice that the entry for TheFile.java has some folded descendants, because its path differs from its predecessor's path by more than one path component. When we detect that, we could render all of the additional path components (dir1/dir2/TheFile.java), not just the filename (TheFile.java).

With this approach, we don't need to store as much redundant state. Does that make sense?

Hi @maxbrunsfeld ,
I've returned to work on the PR and I have a question about the implementation. I've managed to achieve this structure for visible_worktree_entries:

[
     Entry {
         path: "src",
         // ...
     },
     // The entries for the singleton directories `dir1` and `dir2` are omitted,
     // because we decided to fold those single-child directories.
     Entry {
         path: "src/dir1/dir2/TheFile.java",
         // ...
     },
 ]

However, I didn't fully understand how you want them to be rendered properly. So what I did is I took the parent entry from visible_worktree_entries and calculated the difference, then I changed the filename and depth of a child based on that difference. From what I understood, this might not be the way you want it to be rendered. Could you please clarify?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that sounds good to me. I just didn't think we need to maintain additional state for the paths of collapsed directories. It looks like there is still that state on the branch. Are you talking about changes that you haven't pushed up yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have not pushed it yet, still facing issues with some corner cases. Thank you for clarification!

@SomeoneToIgnore
Copy link
Contributor

SomeoneToIgnore commented Feb 12, 2024

A few notes related to the UX, based on a real Java project (https://github.com/vaadin/flow/)

image

Here, flow-test-generic has the action, but it does nothing — I would expect it either to be absent, or actually folding/unfolding the directories below it, even though there's no direct children that can be folded.

image

Here .github directory has nothing foldable in the entire tree, but it has the menu item for some reason.

  • when I unfold the hierarchy of files with the dir collapsed
image

it does close the new unfolded directories, and I have to make an extra click to open the back:

image

that does not seem right to me, as the original, folded view did show those directories as "open".

@jansol
Copy link
Contributor

jansol commented Feb 13, 2024

How does this interact with paths that only have an empty directory at the end? Particularly if you have say, foo/bar and foo/baz and both bar and baz are empty.

@ABckh
Copy link
Contributor Author

ABckh commented Feb 13, 2024

How does this interact with paths that only have an empty directory at the end? Particularly if you have say, foo/bar and foo/baz and both bar and baz are empty.

it would not fold them as foo has 2 children, and bar and baz has no children. Checked in vscode, the behaviour is the same:
Screenshot 2024-02-13 at 7 08 07 PM

And what is the expected behaviour?

@jansol
Copy link
Contributor

jansol commented Feb 13, 2024

I don't really have experience with such functionality so no good references. Not folding seems reasonable there.

And I assume foo/bar/baz/xyz/zy where zy is empty would get folded?

@ABckh
Copy link
Contributor Author

ABckh commented Feb 13, 2024

I don't really have experience with such functionality so no good references. Not folding seems reasonable there.

And I assume foo/bar/baz/xyz/zy where zy is empty would get folded?

Yep, it does not matter if the last dir has children or not

@xerc
Copy link

xerc commented Feb 14, 2024

I don't really have experience with such functionality so no good references. Not folding seems reasonable there.
And I assume foo/bar/baz/xyz/zy where zy is empty would get folded?

Yep, it does not matter if the last dir has children or not

do you consider a empty-directory icon or hide the open-directory chevron?

@ABckh ABckh requested a review from maxbrunsfeld February 26, 2024 09:31
Copy link
Collaborator

@maxbrunsfeld maxbrunsfeld left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for making that refactoring @ABckh. Looks good.

@maxbrunsfeld maxbrunsfeld merged commit 011ae85 into zed-industries:main Feb 26, 2024
7 checks passed
as-cii added a commit that referenced this pull request Feb 27, 2024
as-cii added a commit that referenced this pull request Feb 27, 2024
Reverts #7674

@ABckh: reverting this as it introduced a significant performance
slowdown, most likely caused by iterating through all the snapshot
entries to determine whether a directory is foldable/unfoldable/omitted.
It would be great if you could open a new PR that reverts this revert
and addresses the performance issues. Thank you!

/cc: @maxbrunsfeld 

Release notes:

- N/A
mikayla-maki added a commit that referenced this pull request Apr 12, 2024
Fixed auto folded dirs which caused significant performance issues #8476
(#7674)

Moved from iterating over snapshot entries to use `child_entries`
function from `worktree.rs` by making it public

@maxbrunsfeld 

Release Notes:

- Fixed a bug where project panel settings changes would not be applied
immediately.
- Added a `project_panel.auto_fold_dirs` setting which collapses the
nesting in the project panel when there is a chain of folders containing
a single folder.
<img width="288" alt="Screenshot 2024-04-12 at 11 10 58 AM"
src="https://github.com/zed-industries/zed/assets/2280405/efd61e75-026c-464d-ba4d-90db5f68bad3">

---------

Co-authored-by: Mikayla <mikayla@zed.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla-signed The user has signed the Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants