Commit Graph
9 Commits
Author SHA1 Message Date
Danilo LealandNathan Sobo 4a41cc4bf0 agent_ui: Improve the new thread worktree UX (#53941)
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>
2026-04-15 03:47:19 +00:00
9ffc384185 agent_ui: Unify draft and background threads into retained threads (#53737)
> **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>
2026-04-13 09:07:09 +00:00
8ce9ac3e6a project_panel: Add redo and restore support (#53311)
- 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>
2026-04-09 18:49:16 +01:00
Richard Feldman 8a3effce0f Gracefully handle when linked worktree .git path is outside worktree root (#53443)
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
2026-04-08 15:51:05 -04:00
Max BrunsfeldandEric Holk 83e95f3c7e Maintain root repo common dir path as a field on Worktree (#53023)
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>
2026-04-03 04:16:35 +00:00
Daniel Strobusch 877c2e1b0a worktree: Close single-file worktrees when file is deleted (#49366)
When a single-file worktree's root file no longer exists, the background
scanner would previously enter an infinite retry loop attempting to
canonicalize the path. This caused continuous error logging and resource
waste.

This fix detects when a single-file worktree root cannot be
canonicalized (after attempting the file handle fallback) and emits a
new Deleted event, allowing the worktree to be properly closed.

This is most commonly encountered with temporary files, logs, and
similar files that are opened in Zed and then deleted externally, but
persist in the workspace database across sessions.

Closes #34864





## Test
**Logs** from manual testing:

```
2026-02-17T16:16:11+01:00 INFO  [worktree] inserting parent git repo for this worktree: "tmp.md"
2026-02-17T16:16:17+01:00 ERROR [worktree] root path could not be canonicalized: canonicalizing "/Users/***/tmp/tmp.md": No such file or directory (os error 2)
2026-02-17T16:16:17+01:00 INFO  [worktree] single-file worktree root "/Users/***/tmp/tmp.md" no longer exists, marking as deleted
2026-02-17T16:16:17+01:00 INFO  [worktree] worktree root /Users/***/tmp/tmp.md no longer exists, closing worktree
```
Release Notes:

- Fixed an issue where Zed would enter an infinite retry loop when the
backing file for a single-file worktree was deleted
2026-03-31 15:12:32 -04:00
Ben Kunkle 3795b2ce9d Handle Linux FS Rescan Events (#51208)
Closes #ISSUE

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
- [ ] 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)

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2026-03-17 07:48:44 -05:00
Lukas Wirth b26bc404ea project: Always allocate WorktreeIDs on the remote client (#47936)
Closes https://github.com/zed-industries/zed/issues/40342

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2026-01-29 15:31:13 +00:00
Piotr Osiewicz 00d72f2897 worktree: Use public-api-only tests (#47152)
- **settings: Do not leak type serialization into downstream crates**
- **worktree: Separate integration tests into separate target**

Release Notes:

- N/A
2026-01-22 10:22:04 +01:00