Skip to content

Add basic undo in project panel#47091

Merged
dinocosta merged 68 commits into
zed-industries:mainfrom
marcocondrache:project-panel-undo-redo
Mar 18, 2026
Merged

Add basic undo in project panel#47091
dinocosta merged 68 commits into
zed-industries:mainfrom
marcocondrache:project-panel-undo-redo

Conversation

@marcocondrache
Copy link
Copy Markdown
Contributor

@marcocondrache marcocondrache commented Jan 18, 2026

Initial part for #5039

Continues work from #45008. The author is no longer assigned to the issue, so I’m assuming it’s unclaimed. Please close this if that’s not correct.

  • Undo rename
  • Undo move
  • Undo paste
  • Undo drag
  • Enough tests

Release Notes:

  • N/A

@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented Jan 18, 2026

We require contributors to sign our Contributor License Agreement, and we don't have @HactarCE on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@github-actions github-actions Bot added the community champion Issues filed by our amazing community champions! 🫶 label Jan 18, 2026
@marcocondrache marcocondrache force-pushed the project-panel-undo-redo branch from 14145f1 to 1cf99e0 Compare January 18, 2026 09:48
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Jan 18, 2026
@HactarCE
Copy link
Copy Markdown
Contributor

I no longer work at Zed, but I'm glad someone picked this up. Thank you so much for continuing this!

@HactarCE
Copy link
Copy Markdown
Contributor

@cla-bot check

@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented Jan 18, 2026

The cla-bot has been summoned, and re-checked this pull request!

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
@dinocosta
Copy link
Copy Markdown
Member

Hey @marcocondrache 👋

Thanks for opening this. I was looking at #5039 last week to pick it up and see if we can ship it, so it’s great to see you continuing the work from #45008 !

I paired briefly with @cole-miller today, and we’re planning to update Byron/trash-rs to centralize all trashing and restoring logic there. That crate already provides restoration logic, and both Byron/trash-rs#109 and Byron/trash-rs#128 explore returning the actual item that was trashed, for both Linux and macOS, so that it can be restored. With those changes, it seems we’d only be missing restoration support for macOS as well as returning trashed items on Windows.

If that goes well, we may update these PR changes accordingly, assuming you’re comfortable with that. Let me know if you’re up for some pairing time 🙂

@marcocondrache
Copy link
Copy Markdown
Contributor Author

marcocondrache commented Jan 19, 2026

Hey @dinocosta, thanks for checking this - I had exactly the same idea.

Instead of copying to a temporary folder like in #45008, we can reuse the OS trash and avoid doing the work twice. The current state of the PR already does this (at least on macOS), and I’ve been exploring how to implement it on Linux and Windows as well.

I looked at trash-rs when starting the PR, but I didn’t really like the implementation. It requires passing around handles to trashed items, which gets inconvenient, especially for remote worktrees since they’d need proto serialization. I’m currently working on a separate trash crate that abstracts the platform implementation like trash-rs does and allows restoration by only knowing the old path (I can explain how this works).

I love pairing sessions, so we can arrange a meeting.

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Copy link
Copy Markdown
Member

@dinocosta dinocosta left a comment

Choose a reason for hiding this comment

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

Hey @marcocondrache 👋

Thank you so much for continuing the work on this! I've had a chance to review the current state of these changes and leave some comments in the code, where appropriate.

Some feedback isn't particular to the file or code, so I'll leave it here instead:

  • We'll probably need to think a little bit more on how we undo the ProjectPanelOperation::Batch operation. The current implementation seems to simply pop the operation off the stack and then attempts to undo all the operations within it. However, it seems that, if one of the operations within the batch fails to undo, we halt execution and silently "drop" the remaining operations. I wonder if we'll want to, at least, notify the user of which operations failed.
  • We still need to explore how we're going to deal with conflicts. For example, right now, if I have a src/main.rs file and, through the Project Panel, rename it to src/bananas.rs but then, outside of Zed, create a new src/main.rs file, attempting to undo the rename will silently fail, while also popping the operation from the undo_stack. For the scope of this Pull Request, I believe we only need to care about displaying an error message to the user when undoing an operation fails, possibly with concrete information on what the operation was trying to do, for example, in the case shared above we'd likely want to tell the user that the rename failed because the target file already exists. In a future Pull Request, we might want to explore how to actually provide conflict resolution steps to the user, maybe something as simple as allowing the user to skip the operation or keeping track of the failed operations so we can retry, after the user manually resolves the conflict.
  • Having an "Undo" option option to the right-click menu used in the project panel might also make it easier to discover that this feature exists.
    • Should be disable in case undo_stack.is_empty() is true
    • I might also, in the future, discuss with our design team if there's any icon/indicator/button we want to add for this, to make it easier for folks to know it exists
  • I feel like maybe creating a new crates/project_panel/src/undo.rs module might be a good idea, so we can centralize all this undo/redo system logic and implementation there, especially since crates/project_panel/src/project_panel.rs is already ~6500 lines long.

Hope this helps! Let me know if you have any question or suggestion regarding any of the points or if there's something you'd prefer we pair on. Thanks! 🙂

Comment thread crates/project_panel/src/project_panel.rs Outdated
Comment thread crates/project_panel/src/project_panel.rs Outdated
Comment thread crates/project_panel/src/project_panel.rs Outdated
Comment thread crates/project_panel/src/project_panel.rs Outdated
Comment thread crates/project_panel/src/project_panel.rs Outdated
@marcocondrache marcocondrache force-pushed the project-panel-undo-redo branch from e2c9d9e to 4a31d70 Compare March 5, 2026 18:15
@marcocondrache
Copy link
Copy Markdown
Contributor Author

@dinocosta thanks a lot for reviewing this!

  • I extracted the logic into undo.rs to make it easier to manage and reason about. I've got inspired by https://developer.apple.com/documentation/foundation/undomanager
  • I looked at how VSCode handles conflicts during undo operations. It simply shows a toast notification with the raw error message, I think we can do something similar.
  • I updated the revert logic for ProjectPanelOperation::Batch so it attempts to undo all operations and then collects any errors that occur. We still need to decide how we want to surface or handle errors in this particular case.

marcocondrache and others added 9 commits March 12, 2026 09:13
undo

Update the undo for the `ProjectPanelOperation::Create` operation in
order to trash the file instead of completely deleting. With the current
plans, when we eventually introduce the redo functionality, this is the
outcome the user should expect and, for the time being, it's less
"agressive" to just trash the file. Otherwise one can easily see a
scenario where an user creates a file while in the project panel, starts
writing code on it, maybe updating the codebase to actually use code
from that and then, by accident, focus back on the project panel and
uses the undo keybinding, accidentally deleting all of its work. As
such, it's better to just trash the file for now.
* Update `project_panel::undo::UndoManager::revert_operation` in order
  to return a vector of errors. This way we can determine whether
  undoing the operation failed and return multiple errors in the case of
  a `ProjectPanelOperation::Batch`.
* Introduce `project_panel::undo::UndoManager::show_errors` to display a
  workspace notification with all of the errors that originated when
  attempting to undo a project panel operation.
  * Since we need to be aware of the workspace in order to be able to
    display a workspace notification, `UndoManager::workspace` has also
    been introduced
Since `UndoManager::workspace` now exists in order for the
implementation to be able to show error notifications, we can access the
project trough `Workspace::project`, so this commit removes the
`UndoManager::project` field and updates implementation accordingly.
* Update `project_panel::undo::UndoManager::stack` to be a `VecDeque`
  instead of a `circular_buffer::CircularBuffer`, as Rust's standard
  library already provides a structure for a ring buffer
  * In theory, using `VecDeque` should also make it easier to implement
    the redo functionality in the future, as we can simply keep a
    pointer to the index in the vector where the user's state currently
    is, and any undoing means reverting the opration and decreasing the
    cursor, while redo is performing the action and advancing the cursor
* Introduce `project_panel::undo::UndoManager::new_with_limit` in order
  for us to be able to leverage it in tests
  * Even though all of the tests in the `project_panel` crate live in
    the `project_panel::project_panel_tests` module, I've added a
    `UndoManager` specific test to `project_panel::undo::test`, but we
    can always move it to the `project_panel::project_panel_tests`
    module in the future, if necessary, otherwise I think this is
    cleaner
Update `UndoManager::record` to now take a single operation while
`record_batch` handles multiple, normalising them into a `Batch` or
unwrapping when only one is provided.

This removes the ambiguous `IntoIterator` API and the
`ProjectPanelOperation::batch` smart constructor.
Batch operations are now reverted sequentially rather than in parallel
via `join_all`, and in reverse order to handle dependencies. For
example, if the list of batched operations is one to create the `src/`
folder and another to create the `src/main.rs`, if one tries to trash
the `src/` folder first, it would fail on a non-empty directory.
Copy link
Copy Markdown
Member

@dinocosta dinocosta left a comment

Choose a reason for hiding this comment

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

Hey @marcocondrache ! 👋

Thank you so much for tackling the provided feedback, and sorry for the late reply! I ended up pushing some changes, should be pretty easy for you to review what I changed based on each commit's message but here's a quick overview:

  • Update the revert implementation for Create in order to actually trash and not delete the file
  • Implemented error notifications when undoing a project panel operation fails
  • Refactored UndoManager::stack to use std::colllections::VecDeque instead of circular_buffer::CircularBuffer
    • Since Rust's standard library already provides a structure to implement a ring buffer, I though we could use that instead, only downside is that we need to be the ones ensuring that we respect the operations limit, but that seems okay
    • I believe this will also make it easier to implement redo support, as we could easily keep track of a cursor/index in the vector, such that, undoing an operation moves the decreases the cursor and redoing simply increases the cursor. Any new actions would simply be inserted at the current cursor position, discarding any operations that existed from the cursor to the stack's end

Feel free to take a look at the changes! I'm also organizing next steps and will update you as soon as possible 😀

dinocosta and others added 4 commits March 18, 2026 00:04
Introduce a new `ProjectPanelUndoRedoFeatureFlag` feature flag that
controls whether the undo/redo system is enabled for the project panel,
namely whether the "Undo" context menu item as well as the `Undo` action
handler are enabled.
@dinocosta dinocosta enabled auto-merge (squash) March 18, 2026 22:27
@dinocosta dinocosta merged commit 7baf5dc into zed-industries:main Mar 18, 2026
30 checks passed
@dinocosta dinocosta linked an issue Mar 19, 2026 that may be closed by this pull request
AmaanBilwar pushed a commit to AmaanBilwar/zed that referenced this pull request Mar 20, 2026
- Add `project_panel::undo::UndoManager` with a bounded operation stack
  to track and revert project panel operations
- Support undoing file and directory creation, renaming, moving, pasting
  and drag-and-drop operations
- Revert batch operations sequentially in reverse order to handle
  dependencies between them
- Show an error notification when one or more undo operations fail
- Add "Undo" entry to the project panel context menu, disabled when
  there is nothing to undo
- Gate the feature behind the `project-panel-undo-redo` feature flag

Ref: zed-industries#5039

Release Notes:

- N/A

---------

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: dino <dinojoaocosta@gmail.com>
@dinocosta dinocosta mentioned this pull request Mar 20, 2026
5 tasks
toshmukhamedov pushed a commit to toshmukhamedov/zed that referenced this pull request Mar 20, 2026
- Add `project_panel::undo::UndoManager` with a bounded operation stack
  to track and revert project panel operations
- Support undoing file and directory creation, renaming, moving, pasting
  and drag-and-drop operations
- Revert batch operations sequentially in reverse order to handle
  dependencies between them
- Show an error notification when one or more undo operations fail
- Add "Undo" entry to the project panel context menu, disabled when
  there is nothing to undo
- Gate the feature behind the `project-panel-undo-redo` feature flag

Ref: zed-industries#5039

Release Notes:

- N/A

---------

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: dino <dinojoaocosta@gmail.com>
AmaanBilwar pushed a commit to AmaanBilwar/zed that referenced this pull request Mar 23, 2026
- Add `project_panel::undo::UndoManager` with a bounded operation stack
  to track and revert project panel operations
- Support undoing file and directory creation, renaming, moving, pasting
  and drag-and-drop operations
- Revert batch operations sequentially in reverse order to handle
  dependencies between them
- Show an error notification when one or more undo operations fail
- Add "Undo" entry to the project panel context menu, disabled when
  there is nothing to undo
- Gate the feature behind the `project-panel-undo-redo` feature flag

Ref: zed-industries#5039

Release Notes:

- N/A

---------

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: dino <dinojoaocosta@gmail.com>
piper-of-dawn pushed a commit to piper-of-dawn/zed that referenced this pull request Apr 25, 2026
- Add `project_panel::undo::UndoManager` with a bounded operation stack
  to track and revert project panel operations
- Support undoing file and directory creation, renaming, moving, pasting
  and drag-and-drop operations
- Revert batch operations sequentially in reverse order to handle
  dependencies between them
- Show an error notification when one or more undo operations fail
- Add "Undo" entry to the project panel context menu, disabled when
  there is nothing to undo
- Gate the feature behind the `project-panel-undo-redo` feature flag

Ref: zed-industries#5039

Release Notes:

- N/A

---------

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: dino <dinojoaocosta@gmail.com>
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 community champion Issues filed by our amazing community champions! 🫶

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot undo actions in the project panel

6 participants