Skip to content

fix(editor): let Undo revert every write of a multi-request gesture - #35

Open
helloforvets wants to merge 1 commit into
flowtricks:mainfrom
helloforvets:fix/undo-multi-request-gesture
Open

helloforvets wants to merge 1 commit into
flowtricks:mainfrom
helloforvets:fix/undo-multi-request-gesture

Conversation

@helloforvets

Copy link
Copy Markdown

What

Undo after deleting a node restores the markup but not the imports the delete pruned. Astro then fails the page with <Component> is not defined.

Why

A delete is one gesture of two requests (removeNode in App.tsx): the remove-node, then a set-frontmatter that drops the imports nothing reads any more. The undo step is owed one write when the gesture is queued (addGesture), so the first reply settles it to applied and recordApplied discards the second write's inverse. revertedSteps then reverts only the removal.

Reproduced on 0.1.37: select a wrapper element holding several components in the Navigator, press Backspace, press ⌘Z. The wrapper comes back; its imports do not. The log shows two writes for the delete and one for the undo.

Fix

sendGesture owes the step one more write right before each later request goes out (oweAnother). Owing lazily keeps a retried gesture honest: a request that never went out is never waited for. A record no step reads (a preview's, dropped) stays dropped.

Tests

  • pageEdits.test.js, the fake-send outcome table: the step holds every write of a two-request gesture; nothing extra is owed when the first request is refused with a retry.
  • A new end-to-end case through main's real handlers: delete a wrapper, let the prune follow, revert the step newest first, expect the original file byte for byte.

Both fail without the fix (the undo step holds every write of the gesture, the step waited for both writes) and pass with it. npm run check:changed and the full gate pass.

Aside, unrelated to this change: on a UTC+10 machine the full gate fails one pre-existing case, renderer/history/historyPanel "today is Today". Its fixed now of 15:00Z minus two hours crosses local midnight there, so the group reads "Yesterday". It passes under TZ=UTC, as CI runs.

🤖 Generated with Claude Code

Deleting a node is one gesture of two requests (App.tsx, removeNode):
the removal, then a set-frontmatter that prunes the imports nothing
reads any more. The undo step was owed one write when the gesture was
queued (addGesture), so the first reply settled it to `applied` and
recordApplied dropped the second write's inverse. Undo then put the
nodes back without their imports, and Astro failed the page with
"<Component> is not defined".

sendGesture now owes the step one more write right before each later
request goes out. Owing lazily keeps a retried gesture honest: a request
that never went out (a retry stops at the first) is never waited for.
A record no step reads (a preview's, dropped) stays dropped.

Reproduced on 0.1.37 by deleting a page's wrapper element and pressing
Undo: the wrapper returned, its nine component imports did not.

Tests: the fake-send outcome table pins the step holding every write
of a two-request gesture and nothing extra owed on a retry; an
end-to-end case through main's real handlers deletes a wrapper, lets
the prune follow, reverts the step, and expects the file byte for byte.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant