# Objective
Land five small, independent performance fixes found during an audit of
hot paths (anchor resolution, line shaping, worktree scanning, and
sorting in multibuffers).
## Solution
Each fix is its own commit, so **this PR is best reviewed
commit-by-commit** — every commit message contains the full reasoning
for that change:
- `text`: Avoid redundant rope traversal in `Anchor → usize` conversion
— call `offset_for_anchor` directly instead of `summary_for_anchor`,
which recomputed the same byte offset with ~4 extra O(log n) tree walks.
This is the hottest anchor-resolution path.
- `editor`: Avoid double allocation per shaped line —
`line.as_str().into()` instead of `line.clone().into()`, which allocated
twice per visible line, every frame.
- `text`: Use `sort_unstable_by_key` in operation queue insertion —
Lamport timestamps are unique keys and duplicates are deduped right
after, so stability buys nothing.
- `multi_buffer`: Sort with an explicit comparator instead of
`sort_unstable_by_key`, which cloned a `PathKey` (`Arc` refcount bump)
on every comparison.
- `worktree`: Replace O(n²) `Vec::remove` in the deferred-directory pass
with an O(1) `None` assignment — the vec is already
`Vec<Option<ScanJob>>` and is consumed with `.flatten()`.
## Testing
- No behavior changes intended; all changes are mechanical and tests
affected crates pass: `text`, `editor`, `multi_buffer`, `worktree`.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- Improved editor performance through several micro-optimizations in
anchor resolution, line shaping, and worktree scanning.
# Objective
Add remote (SSH) and collaboration support for trashing and restoring
files in the project panel, which in turn enables undo/redo of trash
operations against remote and collab projects.
Relates to #5039.
## Solution
- Updated the project panel undo system to carry `TrashId` instead of
`TrashedEntry`.
- Using `TrashedEntry` could get hairy, as it includes paths, which
wouldn't play too nicely when using, for exapmle, macOS as the client
and Windows as the host. Using a simple identifier is much easier in
this regard and simplifies implementation.
- Enabled the Trash action and context-menu entry on remote projects,
and removed the command palette filter in `ProjectPanel::new` that was
still hiding the action on remote.
- As far as I can tell, there isn't a reliable way to detect whether a
given remote actually supports the OS trash, so we expose the action
everywhere rather than guessing. On a remote without trash support the
action will fail when invoked but this is a conscious tradeoff until we
find a better way to handle this.
- `fs` now tracks trashed files in a `SlotMap<TrashId, TrashedEntry>` on
each `Fs` implementation. Trashed files are referenced by an opaque
`TrashId` instead of passing a `TrashedEntry` around, which avoids
serializing filesystem paths in remote messages.
- Split the old `delete_entry(trash: bool)` API into distinct
`trash_entry`/`trash_file` (returning a `TrashId`) and
`delete_entry`/`delete_file` across `Project`, `Worktree`,
`LocalWorktree` and `RemoteWorktree`.
- This lets us drop the optional trash result (`Option<TrashedEntry>`)
from the delete path and require a `TrashId` from the trash path.
- Added new proto messages (`TrashProjectEntry`,
`TrashProjectEntryResponse`, `RestoreProjectEntry`,
`RestoreProjectEntryResponse`) to let clients request the host to trash
or restore entries.
- This deprecates `DeleteProjectEntry::use_trash`, but the host still
honors it. An older collab peer may request trashing via that flag
instead of the newer `TrashProjectEntry`. If the host ignored it, a
newer host would permanently delete a file the user meant to send to the
trash. The field will be removed in a later PR once all supported peers
use `TrashProjectEntry`.
## Testing
The following tests were introduced to ensure the new behavior is
correctly tested:
* `remote_server::remote_editing_tests::test_remote_trash_restore` –
Tests trashing a project entry in remote
*
`remote_server::remote_editing_tests::test_remote_delete_project_entry_with_trash`
– Test to ensure we continue respecting `DeleteProjectEntry::use_trash`
until it is fully removed
* `project_panel::tests::undo::trash_directory_undo_redo` – Not related
to these changes but a nice to have as we were missing a test ensuring
that trashing and then undoing and redoing it for a directory works as
expected
Besides these, the following scenarios were manually tested against a
remote session on the same machine (macOS):
- Trashing → Undo (Restore) → Redo (Trashing)
- Batch Trashing → Undo (Batch Restore) → Redo (Batch Trashing)
- Rename → Undo (Rename) → Redo (Rename)
- Move → Undo (Move) → Redo (Move)
- Batch Move → Undo (Batch Move) → Redo (Batch Move)
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: Yara <git@yara.blue>
This is necessary to remove some `util` dependencies from crates, as
well as better sharing for our projects. This also includes the WIP
AbsPath abstraction as well as some bug fixes from internal tooling.
Release Notes:
- N/A or Added/Fixed/Improved ...
# Objective
Let's git ignored directories be opened as their own project
## Solution
- Add an "ignored dir" carve out when checking project collision
## Testing
- Added tests
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [-] Unsafe blocks (if any) have justifying comments
- [-] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [-] Performance impact has been considered and is acceptable
---
Release Notes:
-
# Objective
- Fix ignored file search in nested Git directories (even just empty
`.git` directories, not real git repositories)
- Fixes#52328
## Solution
Keep parent ignore rules when rebuilding a nested repository's ignore
stack. This hides root-ignored files again after excluded-file search is
turned off, without breaking global ignore handling.
For example:
```ascii
project/
├── .git/
├── .gitignore # log/
├── app/
│ └── a.txt # hello
└── log/
├── .git/ # nested repository marker
└── b.txt # hello
```
Both `a.txt` and `b.txt` have string `hello`.
Initially, searching for `hello` returns only `a.txt`. Enabling `Also
search files ignored by configuration` rescans `log/` and returns both
files.
Before this change, disabling the option still
returned both files because the rescan dropped the parent `.gitignore`
and marked `b.txt` as included.
## Testing
- Did you test these changes? If so, how?
To test changes in this pull request create a simple project with the
following dir structure:
```
.git
.gitignore
a/a.txt
b/b.txt
b/.git # this is an empty directory
```
Add `b` folder as an ignore entry to the `.gitignore` file: `b/`
- Are there any parts that need more testing?
No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Use the test scenario above
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
macOS
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
By using the structure above here is how it works before changes here:
https://github.com/user-attachments/assets/2028123e-388e-4390-b131-ddf4642ab5f3
Notice that `hello` string from file `b.txt` is listed in search results
regardless of the option `Include excluded files`
And here is after:
https://github.com/user-attachments/assets/99c627a2-e16a-4fdd-979b-2e0bacbd827d
Notice that `hello` string from file `b.txt` is **not** listed in search
results when the option `Include excluded files` is disabled.
Release Notes:
- Fixed ignored file search in nested Git directories
On Linux and FreeBSD the native file watcher is non-recursive, so a
watch on the .git directory itself does not report changes to files
nested below it. Loose refs live in nested directories under refs, so
external git commit, fetch, branch, and update-ref operations that don't
also touch a direct child of .git (like the index) went entirely
unnoticed.
Watch every directory in the refs tree when a repository is inserted,
and watch directories subsequently created under refs (new remotes,
slash-named branches) as their creation events arrive. On platforms with
recursive watchers these registrations dedupe against the existing
recursive watch, making them free.
---
Release Notes:
- N/A or Added/Fixed/Improved ...
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#57174
Release Notes:
- Open non-writeable files in Capability::Read mode
Co-authored-by: Lukas Wirth <lukas@zed.dev>
update_git_repositories mapped a changed .git path to a repository with
find_map, so when several repositories share a git directory - a main
checkout plus one of its linked worktrees in the same project worktree -
a ref update under the shared common dir only bumped git_dir_scan_id on
whichever repository iterated first, leaving the others stale until an
unrelated event happened to refresh them. Collect every matching
repository and bump each one.
---
Release Notes:
- N/A or Added/Fixed/Improved ...
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#55792
Release Notes:
- Fixed files in pnpm workspaces moving to symlinked `node_modules`
paths after saving.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Summary
- Track whether a worktree root is itself a linked Git worktree.
- Use that metadata when computing project group keys so bare checkout
worktrees group under the repository identity path.
- Propagate the metadata through remote worktree protocols and add
local/remote regression coverage.
Background
Bare checkout layouts can place linked worktrees under the repository
identity directory, e.g. `/monty/.bare` with worktrees like
`/monty/feature-a`. We were treating those linked worktree paths as
separate project identities, which caused the sidebar to move agent
threads under the active worktree instead of the shared repository
group.
We also exclude adding this to collab intentionally, we can open a
different PR for that if we need to.
Closes#59910
Closes AI-431
Test Plan
- `cargo fmt --package project --package worktree --package
remote_server --package workspace --package collab --package proto`
- `git --no-pager diff --check`
- `cargo test -p project test_project_group_key -- --nocapture`
- `cargo test -p remote_server test_remote_root_repo_common_dir --
--nocapture`
- `cargo test -p worktree remote_worktree -- --nocapture`
- `cargo test -p workspace
test_remote_project_root_dir_changes_update_groups -- --nocapture`
- `cargo check -p collab`
Self-Review Checklist:
I've reviewed my own diff for quality, security, and reliability
Unsafe blocks (if any) have justifying comments
The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Tests cover the new/changed behavior
Performance impact has been considered and is acceptable
Release Notes:
- Fixed agent thread/sidebar grouping for Git worktrees backed by bare
checkouts.
---------
Co-authored-by: Anthony Eid <anthony@zed.dev>
Related to #59610.
# Objective
When the filesystem watcher loses sync (common on macOS under heavy
churn, e.g. a dev build constantly rewriting `target/` and `.git/`), it
forces a recursive rescan of the worktree root. That rescan removes the
whole subtree from the snapshot before re-scanning it, and
`remove_path_from_snapshot` was unconditionally pruning the worktree's
git repositories along with it.
Because the scanner publishes intermediate snapshots while it works, a
snapshot could be published in the window after the repository was
pruned but before `.git` was re-scanned. The `GitStore` would see the
repository as removed, tear it down, and then re-create it with a fresh
`RepositoryId` once it reappeared — churning the id on every watcher
overflow and spamming `RepositoryUpdated` events to all consumers (git
panel, git graph, blame, etc.).
Here some debug logs,
**See** that the **repoId** inside the git graph event is different and
is **8** now, even though I only have one repository and didn't do any
git related updates.
```
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for Native; scheduling rescans for 11 registrations
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 WARN [fs::fs_watcher] filesystem watcher lost sync for many files, not logging more
2026-06-26T18:38:44+02:00 INFO [git::repository] opening git repository at "/Users/remcosmits/Documents/code/zed/.git" using git binary "/opt/homebrew/bin/git"
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:44+02:00 ERROR [crates/zed/src/main.rs:1991] Is a directory (os error 21)
2026-06-26T18:38:44+02:00 INFO [project::prettier_store] Prettier config file ".prettierrc" changed, reloading prettier instances for worktree 1
2026-06-26T18:38:45+02:00 INFO [project::prettier_store] Prettier config file ".prettierrc" changed, reloading prettier instances for worktree 1
2026-06-26T18:38:45+02:00 INFO [git::repository] opening git repository at "/Users/remcosmits/Documents/code/zed/.git" using git binary "/opt/homebrew/bin/git"
2026-06-26T18:38:45+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
2026-06-26T18:38:45+02:00 ERROR [crates/git_ui/src/git_panel.rs:3892] oneshot canceled
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
1,
)
[crates/git_ui/src/git_graph.rs:1468:21] "other repo id" = "other repo id"
[crates/git_ui/src/git_graph.rs:1468:21] &updated_repo_id = RepositoryId(
8,
)
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
1,
)
[crates/git_ui/src/git_graph.rs:1468:21] "other repo id" = "other repo id"
[crates/git_ui/src/git_graph.rs:1468:21] &updated_repo_id = RepositoryId(
8,
)
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
1,
)
[crates/git_ui/src/git_graph.rs:1468:21] "other repo id" = "other repo id"
[crates/git_ui/src/git_graph.rs:1468:21] &updated_repo_id = RepositoryId(
8,
)
[crates/git_ui/src/git_graph.rs:1468:21] &this.repo_id = RepositoryId(
1,
)
```
## Solution
This change makes `remove_path_from_snapshot` prune git repositories
only when the path was genuinely removed (`metadata == Ok(None)`), not
during a recursive refresh where the subtree is about to be re-scanned.
Stale repositories are still reaped authoritatively against the
filesystem in `update_git_repositories`.
## Testing
It seems to be that I'm the only that can reproduce this issue
@Anthony-Eid tried reproducing this but couldn't.
**Note**: that I dindn't write a regression test since this is a async
timing issue that I couldn't figure out to write a test for.
Steps how I can reproduce this:
1. Run `cargo run`
2. Open `Zed` as only project
3. Open the git graph
4. Open a rust file e.g. `git_graph.rs`
5. CTRL-C inside the terminal to kill Zed
6. Run `cargo run` see that you have git graph open and a rust file,
note that cargo check is doing it's thing.
7. See within a few seconds that Zed's UI flickers (especially the
project panel & nav bar with the selected repo & branch)
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
**Note**: This PR only fixes that we don't send as many git store
events, so this results in not having to update the nav bar where the
selected repo & branch on every event (that is duplicated in a way).
Result of that we now also fixed a rare case that the git graph commit
entries where gone, this was because we incremented the **repoId** and
the graph couldn't find the repo anymore with the id that it has stored
on the gitGraph struct itself.
**Before**
See that the nav bar with selected repo & branch flickers and the git
graph commits are empty.
https://github.com/user-attachments/assets/0957be7f-e732-4fd0-a950-29c496b6407d
See that the git panel entries flicker and we have an temporary empty
panel.
https://github.com/user-attachments/assets/3b70e45c-c720-4009-aefa-696986d731b4
**After**
See that the nav bar with selected repo & branch does not flicker
anymore and that the git graph keeps showing the commits.
https://github.com/user-attachments/assets/6e8a74f6-4a8e-4b28-ad30-574c2f33c6d9
See that the git panel does not show an empy state and does not flicker
anymore.
https://github.com/user-attachments/assets/1df7aacf-b337-4b81-b195-e67d8554d9da
---
cc @Anthony-Eid Since we where debugging this yesterday.
Release Notes:
- Fixed git repositories being repeatedly torn down and re-created when
the filesystem watcher forced a rescan, which caused redundant git
status refreshes and UI churn.
## Goal
This PR fixes a bug in our file system watcher. Because it matched paths
case sensitively, it didn't account for file systems that are case
insensitive by default (macOS, Windows, etc.). As a result, when
multiple subscribers watched the same path using different casing, Zed
could fail to emit file system events to some of them.
### Reproduction
I reproduced this with the `tsgo` LSP, which lowercases the file path of
the visible worktree root it runs in. Zed subscribes to worktree roots
to receive FS updates — e.g. external edits to a buffer, or git state
changes — but it doesn't normalize the path when subscribing, so the two
casings never matched.
### Fix
Fixing this took longer than expected, because I spent a while deciding
on an approach. I considered three:
- **Follow VS Code's lead:** always treat macOS/Windows as case
insensitive and Linux as case sensitive. Simple, but it would leave a
couple of bugs.
- **Real case the path at registration:** walk each component and use
syscalls to rewrite it to match what the file system shows the user
(e.g. Finder shows `/Project/some`, so a request to watch
`/project/some` becomes `/Project/some`). This had rough edge cases with
symlinks that I didn't want to deal with.
- **Detect via syscalls whether a path is on a case-insensitive
(normalizing) file system and match accordingly** — what I went with.
The one wrinkle is that Windows can mark individual directories
case-sensitive… because Windows.
I also added integration tests to prevent future regressions.
Note: Windows currently defaults to case insensitive; implementing the
actual case sensitivity check for it is left to a follow up PR.
Helps #38109#35861#52376 and maybe #41195
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed missed file system events on case-insensitive filesystems that
could cause stale git state and other sync issues
---------
Co-authored-by: Cole Miller <cole@zed.dev>
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- No unsafe blocks added.
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- No new UI components; behavior better matches user intent for opened
folders.
- [x] Tests cover the new/changed behavior
- Added sibling-subdirectory project group regression coverage.
- Extended subfolder Git-status test to ensure Git still uses the parent
repo while project identity stays at the opened folder.
- [x] Performance impact has been considered and is acceptable
- Change adds one small enum/optional field check when computing
worktree paths; no meaningful performance impact expected.
Closes#57997
Release Notes:
- Fixed project grouping for opened subdirectories that share the same
parent Git repository.
## Screenshots
### Before
<img width="334" height="224" alt="Screenshot 2026-05-28 at 5 29 55 PM"
src="https://github.com/user-attachments/assets/ad5b13c5-11a7-4fa4-a074-a519521641da"
/>
<img width="485" height="201" alt="Screenshot 2026-05-28 at 5 28 36 PM"
src="https://github.com/user-attachments/assets/9cd2c138-92f5-4ff2-bf8f-21cdbeff0b79"
/>
### After
<img width="343" height="253" alt="Screenshot 2026-05-28 at 5 29 40 PM"
src="https://github.com/user-attachments/assets/56a4dca7-f0a1-4530-8c89-3c4773b90486"
/>
<img width="420" height="206" alt="Screenshot 2026-05-28 at 5 29 22 PM"
src="https://github.com/user-attachments/assets/d118340a-955e-4483-9888-4b566f59b931"
/>
---------
Co-authored-by: Anthony Eid <anthony@zed.dev>
Co-authored-by: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com>
Include the changed paths in `UpdatedEntries` events emitted by remote
worktrees.
Previously a remote worktree emitted `Event::UpdatedEntries` with an
empty changeset (`Arc::default()`), discarding the changed paths. The
changeset now carries the real added/updated/removed paths, resolving
removed entries against the previous snapshot.
Release Notes:
- Fixed file change events not reporting changed paths in remote
projects
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#57888
Commit `c19cc4c51e` introduced the bug on
#50412 . This change modified the `remove_path` function to also remove
the path from the watcher:
f0341c96a1/crates/worktree/src/worktree.rs (L3218-L3220)
And when a user modified the global setting and doesn't include `.git`
in it, like:
```jsonc
// ~/.config/zed/settings.json
{
"file_scan_exclusions": ["foo"]
}
```
But then includes it on their local project settings:
```jsonc
// ~/my/local/project/.zed/settings.json
{
"file_scan_exclusions": ["**/.git"]
}
```
It causes zed to stop watching for changes on `.git`
Release Notes:
- Fixed bug where zed stopped watching change on `.git` directory if it
was added to the project local `file_scan_exclusions`
Both cloning and dropping of these has quite a bit of overhead (despite
them being snapshots), so avoid where possible, especially in display
map syncing
Release Notes:
- N/A or Added/Fixed/Improved ...
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: John Tur <john-tur@outlook.com>
Co-authored-by: Ben Kunkle <ben@zed.dev>
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
The non-recursive Linux watcher causes subdirectories inside `.git/` to
need explicit watching. For repos using the reftable backend, all ref
data lives in `.git/reftable/`. Operations in the UI like uncommitting
and creating new branches only modify refs inside `.git/reftable`
without changing `.git/HEAD`'s contents, so no inotify event fires on
`.git/` itself and the git UI never refreshes.
Essentially all this change does is check if `.git/reftable/` exists and
if it does, add it to the watcher. On the recursive macOS/Windows
watchers, `FsWatcher::add` returns early safely so this *should* not be
a performance loss apart from the brief lookup.
Release Notes:
- Fixed Git UI not refreshing on Linux for repositories using the
reftable backend.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes #ISSUE
Release Notes:
- N/A or Added/Fixed/Improved ...
Fixes#58619.
When a worktree is opened through a symlinked root, filesystem events
can arrive rooted at either the opened symlink path or the canonical
target path. The worktree event processing path already handled
canonical target paths, but dropped events reported under the opened
symlink root because it only derived relative paths from the canonical
root.
This PR adds a regression test that opens `/link -> /target`, renames
`/link/subdir-a` to `/link/subdir-aa`, and verifies
`subdir-aa/config.ini` remains visible in the worktree. The production
fix accepts event paths under the opened worktree root as a fallback
when deriving relative paths.
Testing:
- Verified the new regression test fails with only the test commit
applied.
- `cargo test -p worktree --test integration
test_renaming_subdir_under_symlinked_root_keeps_children`
- `cargo test -p worktree --test integration
test_symlinks_pointing_outside`
Adds option to always search/scan symlinks for more thorough coverage of
#41887 issue
This is a significant rewrite and more thoroughly reviewed and tested
version of the old PR here:
https://github.com/zed-industries/zed/pull/46344
The "never" option was removed from the old PR, since "expanded" is now
the default. Perhaps "never" can be added as an option later if there's
demand for it. Adding that option may resolve#48890 for instance.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
(significant impact with "always" option, but "expanded" is default)
Release Notes:
- Add option choose between including expanded symlinks or include all
symlinks in project search (#41887)
---------
Co-authored-by: Eric Holk <eric@zed.dev>
When a linked worktree receives fs events for its .git directory, the
event path resolves to the per-worktree git dir (e.g.
main_repo/.git/worktrees/<name>), not the .git directory itself or the
common dir. The existing match only checked common_dir_abs_path and
repository_dir_abs_path, causing the repository entry to be missed and
then removed as stale.
Add dot_git_abs_path to the match, and fix the staleness metadata check
to use dot_git_abs_path (the actual .git entry) rather than
common_dir_abs_path (which may be outside the worktree root).
Extracted from https://github.com/zed-industries/zed/pull/53453
Release Notes:
- N/A or Added/Fixed/Improved ...
---------
Co-authored-by: Kieran Freitag <kfreitag@kieran.ca>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
Patterns in `.git/info/exclude` that contain a slash (e.g.
`.claude/worktrees`) are anchored: Git matches them relative to the
project root. Zed was instead matching them relative to the `.git/info/`
directory that the file lives in, so they matched nothing and had no
effect.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Support anchored patterns in .git/info/exclude
---------
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
Zed reloads a lot of data about a git repository any time any file
changes inside of the `.git` directory, with the exception of a few
known paths that we know do not warrant a reload, such as `index.lock`
and `COMMIT_MESSAGE`. Previously, we ignored FS events for those files,
but we used a specific path that only worked for the main worktree. This
caused a lot of unnecessary reloads when using linked worktrees. Now we
ignore those files in a general way, by their filename, so that the
optimization applies to linked worktrees as well.
@cole-miller Noticed this bug.
Release Notes:
- Fixed unnecessary reloading of Git state that could occur when editing
in linked worktrees.
This PR changes the git store's `compute_snapshot`, which runs to update
state that depends on the contents of `.git`, to degrade gracefully when
fetching individual pieces of state fails. For example, when fetching
the list of branches fails, instead of returning early from the function
(leaving the previous git state snapshot in place with stale state), we
continue with an empty list of branches. This prevents failures of
individual git commands from making the entire git UI get stuck
indefinitely.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes #ISSUE
Release Notes:
- Fixed an issue where failing to fetch branches using the git CLI would
prevent other git-related state from being updated.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: Ben Kunkle <ben@zed.dev>
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#56021Closes#56100
Release Notes:
- N/A or Added/Fixed/Improved ...
Closes https://github.com/zed-industries/zed/issues/54824
Previously, we always assumed that `gitdir` was an absolute path. Also,
we did not correctly handle custom gitignore files that were configured
via separate git directories.
Release Notes:
- Fixed failure to recognize git repositories where `gitdir` was
expressed as a relative path.
- Fixed handling of gitignores in git repositories that use a separate
git dir.
Closes#50880
When a git worktree linked via a `.git` file (e.g. `gitdir:
/repo/.git/worktrees/my-worktree`) was opened in Zed, entries in
`.git/info/exclude` were not respected. This is now fixed.
Before you mark this PR as ready for review, make sure that you have:
- [x] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- Fixed `.git/info/exclude` not being respected when opening a secondary
git worktree
https://github.com/user-attachments/assets/f38df5dc-96eb-40a8-a77c-0932a2c8575b
---------
Co-authored-by: Lukas Wirth <lukas@zed.dev>
Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes #ISSUE
Release Notes:
- N/A
No, sadly, the title is not a typo. See
https://www.githubstatus.com/incidents/zsg1lk7w13cf for the context.
I'll read with joy and popcorn through that root cause analysis.
It makes literally zero sense what happened here, but for some completly
bonkers reason GitHub completely messed up the merge queue with
https://github.com/zed-industries/zed/pull/54632.
I have no idea how it happened. It makes literally zero sense. A PR
going into the merge queue should have the same LoC when getting out of
it. GitHub obviously does not check this. GitHub causes extra work with
a feature that is supposed to save time.
Thanks, I guess.
Release Notes:
- N/A
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
This PR brings back the button to filter remote branches when accessing
the title bar's branch picker with the mouse. It was unintentionally
removed when we introduced the new worktree picker.
Release Notes:
- N/A
Opening an empty file then writing binary content to it on disk causes a
permanent freeze (not a crash — requires force kill).
`reload_impl` loads raw bytes via `load_bytes` and decodes with
`encoding_rs` but never checks if the content is binary. The existing
binary check in `decode_file_text` only runs on fresh opens, not
reloads. So binary content enters the buffer as lossy UTF-8.
Binary data has almost no newlines, producing a single enormous row. The
wrap map's sync fast path in `flush_edits` checks row count (< 100 rows)
but not line length, so it runs `wrap_line` on a multi-MB single line
synchronously on the main thread via `smol::block_on`. Font shaping
millions of non-ASCII replacement characters blocks the UI thread
indefinitely.
Two fixes, both one-condition guards:
- Null-byte check in `reload_impl` before decoding, same heuristic
(first 8000 bytes) used by `decode_file_text` on fresh opens. Binary
content never enters the buffer.
- Column-length guard (`MAX_SYNC_WRAP_COLUMNS = 10_000`) on the wrap map
sync fast path so absurdly long lines fall through to the async
background path. Defense in depth for any single-line content that's too
long to shape synchronously.
## Test plan
- [ ] Open an empty file in Zed, write binary content to it externally
(e.g. `cp /bin/ls /path/to/open-file`) — should show "Binary files are
not supported" instead of freezing
- [ ] Open a compressed file (zip, gz) that starts empty and gets filled
— same behavior
- [ ] Normal text file reload still works (no regression)
- [ ] Very long single-line text files (>10k columns) don't freeze the
editor
---------
Co-authored-by: deadcode-walker <268043493+deadcode-walker@users.noreply.github.com>
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Previously the worktree's handling of events inside gitdirs looked like
this:
- First, deduplicate paths for which we received events by dropping any
path that is a suffix of another one
- Then, filter out events for deliberately ignored paths like
`.git/index.lock`
- Finally, collect a set of affected gitdirs based on the paths that
remain
This doesn't work on Windows, because when events occur for paths inside
`.git` we also get an event for `.git` itself. The deduplication steps
drops `.git/index.lock` before we get the chance to filter it out in the
second step. This causes us to rescan git state unnecessarily on
Windows.
This PR fixes the issue by moving the filtering of ignored paths, and
also the handling of `.git/info/exclude`, to just before the
deduplication step. We also filter out events for the `.git` directory
itself, so that if the batch of events looks like `[".git",
".git/index.lock"]`, we don't trigger `WorktreeUpdatedGitRepositories`.
Self-Review Checklist:
- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable
Closes #ISSUE
Release Notes:
- N/A or Added/Fixed/Improved ...
The `project_name` worktree setting was added in #36713 to let users
override the name shown in the window title. Its description ("The
displayed name of this project. If left empty, the root directory name
will be displayed.") suggests broader coverage, and #46440 reports the
reasonable expectation that it should also apply in the project
switcher. In practice the setting has only ever affected
`Workspace::update_window_title`, so everywhere else (recent projects,
the multi-worktree pane, ...) keeps falling back to the worktree root
name.
Rather than plumb the setting through each of those surfaces, I'm
removing it. Having a project-level setting control how your editor
displays the project has downsides. For example it means a checkout can
dictate UI in someone else's Zed. The natural home for a custom display
name is the workspace DB, set from the UI, which is what we should do if
we want this feature back.
If you want this back, the path forward is to store the display name in
`WorkspaceDb`, expose a UI affordance to edit it, and read it from
`update_window_title`, `recent_projects::get_recent_projects` /
`get_open_folders`, and any other places that currently derive a display
name from the worktree root.
Closes#46440
Release Notes:
- Removed the `project_name` project setting. It only ever affected the
OS window title, and the expectation that it would show up in the
project switcher and elsewhere is better served by a future UI-driven,
per-workspace setting stored locally.
This reverts #54329 and the part of #52499 that was an earlier attempt
at the same thing, which caused us to incorrectly miss git state updates
on Windows. cc @Veykril it seems like we need to find a different way to
fix the problem of `.git` scanning cycles.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed a bug causing stale git state on Windows.
Closes#48729, closes#27263, closes#45954
This PR aims to make zed responsive on symlinked directory events
outside the editor.
Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
new-linked-folder is inside /zed-test/zed-project
output of ls -ld new-linked-folder
`lrwxr-xr-x 1 prayanshchhablani staff 42 28 Mar 23:20 new-linked-folder
-> /Users/prayanshchhablani/new-target-folder`
this shows new-linked-folder is a symlink folder whose target is
new-target-folder which is outside the root dir of the project opened in
zed.
https://github.com/user-attachments/assets/ffebafc3-2fc4-4293-bdbf-3a894a45e276
Release Notes:
- Fixed file watching of symlinks that point outside of the
project/watched directory. Zed should now properly respond to changes in
files in symlinked directories
## Summary
Fixes a crash I hit running Zed Preview against a checkout with many
linked git worktrees. The panic was:
```
thread '<unnamed>' panicked at crates/worktree/src/worktree.rs:5334:25:
update_git_repositories: .git path outside worktree root is not a gitfile: "/Users/eric/repo/zed/.git"
```
The `debug_assert!` in `update_git_repositories` was added in #53443 to
catch the case where a `.git` path outside the worktree root is not a
gitfile. The comment there explained that a `.git` outside the root
should always be a gitfile (as in a linked worktree or submodule), so
the assertion was meant to flag "should never happen" paths.
But there's a second legitimate case: after a linked worktree's
repository has been unregistered from `git_repositories` (for example
because its gitfile was removed, or because the filesystem watcher for
the common git dir lost sync and rescan-driven cleanup dropped the
entry), a subsequent rescan event on the main repo's `.git` directory
arrives at the linked worktree's scanner with the common git dir as the
`dot_git_dir`. That path:
- is outside the linked worktree's root (so it doesn't strip-prefix
cleanly), and
- is a real directory (not a gitfile), because it's the main repo's
`.git`.
So the assertion fires, but `continue` is already the right thing to do
— there's simply nothing left for this scanner to do with a path that
isn't its repository anymore.
On macOS, the trigger in practice is the FSEvents API setting
`MustScanSubDirs` / `UserDropped` / `KernelDropped` on an event (which
`notify` surfaces as `need_rescan()`), which our `FsWatcher` converts
into a `PathEvent { path: <watched path>, kind: Rescan }`. Because every
linked worktree registers a watcher on the same shared common git dir,
one kernel drop fans out into many rescan callbacks, and any one of them
hitting a worktree whose repo was just unregistered triggers the panic.
## Changes
- `crates/worktree/src/worktree.rs` — drop the `debug_assert!`, broaden
the comment to cover both cases.
- `crates/worktree/tests/integration/main.rs` — add a failing regression
test that drives the exact sequence (repo unregistered, then a Rescan
event on the common git dir) and asserts it doesn't panic.
The two commits are split so the test commit reproduces the panic on its
own, and the fix commit on top makes it pass.
Release Notes:
- N/A
Closes https://github.com/zed-industries/zed/issues/53262
- Remove the ability to pick a branch from the agent panel; delegate
this to the title bar picker
- Make the worktree creation earger, just as you selected whether you
want to create it from main or current branch
- Remove flicker when creating a new worktree and switching to a
previously existing one
- Improve some UI stuff: how we display that a worktree is
creating/loading, the branch and worktree icons, etc.
- Fixed a bug where worktrees in a detached HEAD state wouldn't show up
in the worktree pickers
A big part of the diff of this PR is the removal of everything involved
with the `StartThreadIn` enum/the set up involved in only creating the
worktree by the time of the first prompt send.
Release Notes:
- Agent: Improved and simplified the UX of creating threads in Git
worktrees.
- Git: Fixed a bug where worktrees in a detached HEAD state wouldn't
show up in the worktree picker.
---------
Co-authored-by: Nathan Sobo <nathan@zed.dev>
> **Foundation PRs:** #53732, #53733, #53734 — These three draft PRs
contain the base refactors (retained workspaces, agent panel overlay
split, ThreadId introduction) that this PR builds on.
## Goal
Remove `DraftId` and merge `draft_threads` + `background_threads` into a
single `retained_threads: HashMap<ThreadId, Entity<ConversationView>>`
in `AgentPanel`. A draft is just a thread that hasn't sent its first
message — no separate identity or storage needed.
## Changes
### agent_panel.rs
- Remove `DraftId` / `DraftIdCounter` / the `Global` impl
- Merge the two maps into `retained_threads`
- Add `thread_id: ThreadId` field to `BaseView::AgentThread`
- Rename methods: `create_draft` → `create_thread`, `activate_draft` →
`activate_retained_thread`, `remove_draft` → `remove_thread`, etc.
- Replace `clear_active_thread` with `show_or_create_empty_draft`
- Update `update_thread_work_dirs` to sync `ThreadMetadataStore` paths
when worktrees change
- Keep `load_agent_thread(...)` cleanup so activating a real thread
removes empty retained drafts
### sidebar.rs
- Remove `active_entry` derivation from `rebuild_contents` (was racing
with deferred effects)
- Add `sync_active_entry_from_panel` called from event handlers instead
- Simplify `ActiveEntry` — remove `ThreadActivation` struct, make
`session_id` optional
- Move `seen_thread_ids` to global scope (was per-group, causing
duplicate thread entries)
- Remove dead code: `clear_draft`, `render_draft_thread`
- Generalize `pending_remote_thread_activation` into
`pending_thread_activation` so all persisted-thread activations suppress
fallback draft reconciliation
- Set the activation guard before local persisted-thread activation
switches workspaces
- Make `reconcile_groups(...)` bail while a persisted-thread activation
is in flight
- On `ActiveViewChanged`, clear empty group drafts as soon as a pending
persisted-thread activation resolves
### thread_metadata_store.rs
- Make `ThreadMetadata.title` an `Option<SharedString>` with
`display_title()` fallback
- Add `update_worktree_paths` for batched path updates when project
worktrees change
### Other crates
- Update all `ThreadMetadata` construction sites and title display sites
across `agent_ui` and `sidebar`
## Fallback draft invariant
This PR now tightens the retained-thread invariant around fallback
drafts vs real thread activation/restoration:
- Fallback drafts are always empty
- User-created drafts worth preserving are non-empty
- While a persisted thread is being activated/restored/loaded, sidebar
reconciliation must not create an empty fallback draft for that target
group/workspace
- Once the real thread becomes active, empty fallback drafts in that
target group are removed
This is enforced by the sidebar-side activation guard plus existing
`AgentPanel` empty-draft cleanup after real-thread load.
## Tests
Added and/or kept focused sidebar regression coverage for:
-
`test_confirm_on_historical_thread_in_new_project_group_opens_real_thread`
-
`test_unarchive_into_inactive_existing_workspace_does_not_leave_active_draft`
-
`test_unarchive_after_removing_parent_project_group_restores_real_thread`
- `test_pending_thread_activation_suppresses_reconcile_draft_creation`
Focused test runs:
- `cargo test -p sidebar activate_archived_thread -- --nocapture`
- `cargo test -p sidebar unarchive -- --nocapture`
- `cargo test -p sidebar archive_last_thread_on_linked_worktree --
--nocapture`
- `cargo test -p sidebar
test_confirm_on_historical_thread_in_new_project_group_opens_real_thread
-- --nocapture`
- `cargo test -p sidebar
test_unarchive_into_inactive_existing_workspace_does_not_leave_active_draft
-- --nocapture`
- `cargo test -p sidebar
test_unarchive_after_removing_parent_project_group_restores_real_thread
-- --nocapture`
- `cargo test -p sidebar
test_pending_thread_activation_suppresses_reconcile_draft_creation --
--nocapture`
## Test fix
Fixed flaky `test_backfill_sets_kvp_flag` — added per-App `AppDatabase`
isolation in `setup_backfill_test` so backfill tests no longer share a
static in-memory DB.
Release Notes:
- N/A
---------
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Mikayla Maki <mikayla@zed.dev>
- Introduce `project_panel::Redo` action
- Update all platform keymaps in order to map
`redo`/`ctrl-shift-z`/`cmd-shift-z` to the `project_panel::Redo` action
### Restore Entry Support
- Update both `Project::delete_entry` and `Worktree::delete_entry` to
return the resulting `fs::TrashedEntry`
- Introduce both `Project::restore_entry` and `Worktree::restore_entry`
to allow restoring an entry in a worktree, given the `fs::TrashedEntry`
- Worth pointing out that support for restoring is not yet implemented
for remote worktrees, as that will be dealt with in a separate pull
request
### Undo Manager
- Split `ProjectPanelOperation` into two different enums, `Change` and
`Operation`
- While thinking through this, we noticed that simply recording the
operation that user was performing was not enough, specifically in the
case where undoing would restore the file, as in that specific case, we
needed the `trash::TrashedEntry` in order to be able to restore, so we
actually needed the result of executing the operation.
- Having that in mind, we decided to separate the operation (intent)
from the change (result), and record the change instead. With the change
being recorded, we can easily building the operation that needs to be
executed in order to invert that change.
- For example, if an user creates a new file, we record the
`ProjectPath` where the file was created, so that undoing can be a
matter of trashing that file. When undoing, we keep track of the
`trash::TrashedEntry` resulting from trashing the originally created
file, such that, redoing is a matter of restoring the
`trash::TrashedEntry`.
- Refer to the documentation in the `project_panel::undo` module for a
better breakdown on how this is implemented/handled.
- Introduce a task queue for dealing with recording changes, as well as
undo and redo requests in a sequential manner
- This meant moving some of the details in `UndoManager` to a
`project_panel::undo::Inner` implementation, and `UndoManager` now
serves as a simple wrapper/client around the inner implementation,
simply communicating with it to record changes and handle undo/redo
requests
- Callers that depend on the `UndoManager` now simply record which
changes they wish to track, which are then sent to the undo manager's
inner implementation
- Same for the undo and redo requests, those are simply sent to the undo
manager's inner implementation, which then deals with picking the
correct change from the history and executing its inverse operation
- Introduce support for tracking restore changes and operations
- `project_panel::undo::Change::Restored` – Keeps track that the
file/directory associated with the `ProjectPath` was a result of
restoring a trashed entry, for which we now that reverting is simply a
matter of trashing the path again
- `project_panel::undo::Operation::Restore` – Keeps track of both the
worktree id and the `TrashedEntry`, from which we can build the original
`ProjectPath` where the trashed entry needs to be restored
- Move project panel's undo tests to a separate module
`project_panel::tests::undo` to avoid growing the
`project::project_panel_tests` module into a monolithic test module
- Some of the functions in `project::project_panel_tests` were made
`pub(crate)` in order for us to be able to call those from
`project_panel::tests::undo`
### FS Changes
- Refactored the `Fs::trash_file` and `Fs::trash_dir` methods into a
single `Fs::trash` method
- This can now be done because `RealFs::trash_dir` and
`RealFs::trash_file` were simply calling `trash::delete_with_info`, so
we can simplify the trait
- Tests have also been simplified to reflect this new change, so we no
longer need a separate test for trashing a file and trashing a directory
- Update `Fs::trash` and `Fs::restore` to be async
- On the `RealFs` implementation we're now spawning a thread to perform
the trash/restore operation
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Relates to #5039
Release Notes:
- N/A
---------
Co-authored-by: Yara <git@yara.blue>
Co-authored-by: Miguel Raz Guzmán Macedo <miguel@zed.dev>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Update both `Fs::trash_dir` and `Fs::trash_file` to now return the
location of the trashed directory or file, as well as adding the
`trash-rs` create dependency and updating the `RealFs` implementation
for these methods to simply leverage `trash::delete_with_info`.
* Add `fs::Fs::TrashedEntry` struct, which allows us to track the
original file path and the new path in the OS' trash
* Update the `fs::Fs::trash_dir` and `fs::Fs::trash_file` signatures to
now return `Result<TrashedEntry>` instead of `Result<()>`
* The `options` argument was removed because it was never used by
implementations other than the default one, and with this change to
the signature type, we no longer have a default implementation, so the
`options` argument would no longer make sense
* Update `fs::RealFs::trash_dir` and `fs::RealFs::trash_file`
implementations to simply delegate to `trash-rs` and convert the
result to a `TrashedEntry`
* Add `fs::FakeFs::trash` so we can simulate the OS' trash during tests
that touch the filesystem
* Add `fs::FakeFs::trash_file` implementation to leverage
`fs::FakeFs::trash`
* Add `fs::FakeFs::trash_dir` implementation to leverage
`fs::FakeFs::trash`
This PR greatly improves our handling of remote threads in the sidebar.
One primary issue was that many parts of the sidebar were only looking
at a thread's path list and not its remote connection information. The
fix here is to use `ProjectGroupKey` more consistently throughout the
sidebar which also includes remote connection information.
The second major change is to extend the MultiWorkspace with the ability
to initiate the creation of remote workspaces when needed. This involved
refactoring a lot of our remote workspace creation paths to share a
single code path for better consistency.
Release Notes:
- (Preview only) Fixed remote project threads appearing as a separate
local project in the sidebar
---------
Co-authored-by: Anthony Eid <anthony@zed.dev>
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
In `update_git_repositories`, a `.git` path outside the worktree root
can occur legitimately when `.git` is a gitfile (as in linked worktrees
and submodules) pointing to a directory in the parent repo. Previously
this triggered a `debug_panic!`, crashing debug builds.
Now we skip the path with a `debug_assert!` that it is indeed a file
(not a directory), so a genuine `.git` directory outside the worktree
root would still be caught in debug builds.
(No release notes because this is extremely hard to encounter until
https://github.com/zed-industries/zed/pull/53215 lands)
Release Notes:
- N/A
This PR makes sidebar deserialization enforce the invariants that the
multiworkspace is supposed to enforce. Also, this PR makes it so that
failing to deserialize the active workspace no longer totally fails to
deserialize the multiworkspace.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
This enables us to always different git worktrees of the same repo
together.
Depends on https://github.com/zed-industries/cloud/pull/2220
Release Notes:
- N/A
---------
Co-authored-by: Eric Holk <eric@zed.dev>