Skip to content

fix: return the caret to the edit projection-local undo and redo reverse - #412

Merged
Azganoth merged 1 commit into
mainfrom
bug/projection-history-caret
Sep 5, 2026
Merged

fix: return the caret to the edit projection-local undo and redo reverse#412
Azganoth merged 1 commit into
mainfrom
bug/projection-history-caret

Conversation

@Azganoth

@Azganoth Azganoth commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

Projection-local Undo and Redo restored the source correctly but set the caret to the end of the projected range whatever they restored, so every step lost the author's place, and the further the edit sat from the end of the source the further the caret jumped.

The stacks held whole source strings, which cannot recover a caret on their own: the same source can be reached from different positions. Each entry now carries the selection the document held while it held that source, as offsets into it, so an entry survives the range moving under it. A change records the selection in effect before it, and a step pushes the current selection onto the opposite stack, so Undo returns to where the author was standing and Redo to where the edit left them. Recording the whole selection rather than a caret follows from the same model: an edit that replaced a selection is undone back onto that selection.

That model is prosemirror-history's own, which is what decides the question #411 leaves open. Local history is what the author reaches before the native history a session hands off to once its own history runs out, and the two now agree on where a reversed edit leaves the caret rather than differing across a seam the author cannot see.

Deriving the caret by diffing the restored source against the current one was the alternative. Reading only the two sources, it cannot see an edit an adapter remapped out of a delimiter, and it resolves to the wrong end of a run of repeated characters, where a common prefix and suffix leave the position genuinely ambiguous.

Related Issue

Closes #411

Verification

pnpm check:frontend passes on the complete change.

Focused tests in sourceProjectionIntegration.test.ts prove that an edit away from the end of the source returns the caret to that edit in both directions, over a marked fragment and over a link, while the text each step restores is unchanged. Both fail against the plugin as it stands before this change, landing at the end of the projected range on the positions #411 reports. The existing tests for a session exhausting its local history and for stepping over a composed, unauthored write are untouched and still pass.

Not verified in this session: a pass in the running application. The change is caret placement, which the editor mount the plugin tests drive measures directly.

The local stacks held whole source strings, so every step set the caret
to the end of the projected range whatever it restored, and an edit away
from the end lost the author's place.

Each entry now carries the selection the document held while it held
that source, which mirrors prosemirror-history: a change records the
selection in effect before it, and a step pushes the current selection
onto the opposite stack. Local history is what the author reaches
before the native history it hands off to, so the two agree on where a
reversed edit leaves the caret.

Deriving the caret by diffing the restored source against the current
one was rejected. It cannot see an edit an adapter remapped out of a
delimiter, and it resolves to the wrong end of a run of repeated
characters, where the common prefix and suffix leave the position
ambiguous.
@Azganoth Azganoth added the Bug Something isn't working label Sep 5, 2026
@Azganoth Azganoth self-assigned this Sep 5, 2026
@Azganoth
Azganoth enabled auto-merge (squash) September 5, 2026 23:55
@Azganoth
Azganoth merged commit e9c79a8 into main Sep 5, 2026
3 checks passed
@Azganoth
Azganoth deleted the bug/projection-history-caret branch September 5, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Projection-local Undo and Redo leave the caret at the end of the projected source

1 participant