Undo mutations after :w #35

Closed
opened 2026-09-21 18:54:22 +00:00 by barrettruth · 1 comment
Owner

Original issue: barrettruth/canola.nvim#191
Original author: barrettruth
Original date: 2026-03-19T03:03:30Z

Problem

After saving mutations with :w (rename, delete, move, create), pressing u in the oil buffer reports "already at latest change". Neovim's undo tree tracks buffer text only — it has no knowledge of the filesystem operations that were performed. There is no way to reverse a confirmed mutation through the editor.

Consolidates

Scope

The feature requested in both issues is the same: after confirming mutations, the user should be able to undo them — ideally with u as they would any other edit, or at minimum via a dedicated action.

The difficulty is that filesystem operations are not atomic and not uniformly reversible:

  • Rename / move: reversible — rename back.
  • Create (empty file/dir): reversible — delete the created entry.
  • Copy: reversible — delete the copy.
  • Delete to trash: reversible — restore from trash.
  • Permanent delete: not reversible. Data is gone.

A mutation undo stack would need to record the inverse operation for each action at execution time and replay inverses in reverse order. Partial undo (rolling back only some operations in a batch) is especially hard when later operations depend on earlier ones (e.g., move A → B, then move B → C: undoing only the second step is valid, but undoing only the first is not).

Approach options

Option A — dedicated undo action: a undo_last_mutations action that replays the inverse of the most recently confirmed batch. Does not integrate with u; user binds it explicitly. Simpler to implement and explain.

Option B — hook into Neovim undo: after mutations complete, synthesize a buffer change that represents the inverse state (re-render the pre-mutation buffer text), so u naturally reverts the buffer and the next :w re-applies the inverse operations. Clever but fragile — the undo entry would need to survive buffer re-renders triggered by the mutation itself.

Option A is more realistic. Option B has too many edge cases with how oil re-renders the buffer after each :w.

Constraints

  • Permanent deletes (without trash) cannot be undone regardless of approach. The undo stack must clearly communicate when the oldest recoverable point has been reached.
  • The undo stack is session-local. It does not persist across restarts.
  • Stevearc labeled this P1 upstream but has not implemented it. It is genuinely complex.

Complexity

High. Requires a parallel mutation log alongside Neovim's undo tree, inverse-operation computation for each action type, and careful interaction with the buffer re-render that follows every :w.

> Original issue: barrettruth/canola.nvim#191 > Original author: `barrettruth` > Original date: 2026-03-19T03:03:30Z ## Problem After saving mutations with `:w` (rename, delete, move, create), pressing `u` in the oil buffer reports "already at latest change". Neovim's undo tree tracks buffer text only — it has no knowledge of the filesystem operations that were performed. There is no way to reverse a confirmed mutation through the editor. ## Consolidates - stevearc/oil.nvim#95 (undo after rename — same root problem) ## Scope The feature requested in both issues is the same: after confirming mutations, the user should be able to undo them — ideally with `u` as they would any other edit, or at minimum via a dedicated action. The difficulty is that filesystem operations are not atomic and not uniformly reversible: - **Rename / move**: reversible — rename back. - **Create (empty file/dir)**: reversible — delete the created entry. - **Copy**: reversible — delete the copy. - **Delete to trash**: reversible — restore from trash. - **Permanent delete**: not reversible. Data is gone. A mutation undo stack would need to record the inverse operation for each action at execution time and replay inverses in reverse order. Partial undo (rolling back only some operations in a batch) is especially hard when later operations depend on earlier ones (e.g., move A → B, then move B → C: undoing only the second step is valid, but undoing only the first is not). ## Approach options **Option A — dedicated undo action**: a `undo_last_mutations` action that replays the inverse of the most recently confirmed batch. Does not integrate with `u`; user binds it explicitly. Simpler to implement and explain. **Option B — hook into Neovim undo**: after mutations complete, synthesize a buffer change that represents the inverse state (re-render the pre-mutation buffer text), so `u` naturally reverts the buffer and the next `:w` re-applies the inverse operations. Clever but fragile — the undo entry would need to survive buffer re-renders triggered by the mutation itself. Option A is more realistic. Option B has too many edge cases with how oil re-renders the buffer after each `:w`. ## Constraints - Permanent deletes (without trash) cannot be undone regardless of approach. The undo stack must clearly communicate when the oldest recoverable point has been reached. - The undo stack is session-local. It does not persist across restarts. - Stevearc labeled this P1 upstream but has not implemented it. It is genuinely complex. ## Complexity High. Requires a parallel mutation log alongside Neovim's undo tree, inverse-operation computation for each action type, and careful interaction with the buffer re-render that follows every `:w`.
barrettruth added this to the v1.1 milestone 2026-09-21 18:54:22 +00:00
Author
Owner

Original comment: barrettruth/canola.nvim#191, comment 4102187995
Original author: barrettruth
Original date: 2026-03-21T03:59:45Z

Closing — the confirmation dialog already prevents accidental mutations, and "just rename it back" covers the common case. A parallel undo stack adds significant complexity (inverse computation, batch ordering, partial failure handling) for marginal UX improvement. stevearc labeled this P1 upstream 3 years ago and never shipped it.

> Original comment: barrettruth/canola.nvim#191, comment 4102187995 > Original author: `barrettruth` > Original date: 2026-03-21T03:59:45Z Closing — the confirmation dialog already prevents accidental mutations, and "just rename it back" covers the common case. A parallel undo stack adds significant complexity (inverse computation, batch ordering, partial failure handling) for marginal UX improvement. stevearc labeled this P1 upstream 3 years ago and never shipped it.
Sign in to join this conversation.
No description provided.