fix(extmarks): undo-redo of a mark explicitly moved during an edit #41252

Problem:
A mark moved by nvim_buf_set_extmark() during an edit is misplaced by
undo and redo. Only splices ("edits") are recorded, and replaying them
reproduces the shifts they caused, never the explicit set: the mark ends
up wherever the text pushed it.

Solution:
When an open undo block moves an existing mark, record both positions.
Undo restores the pre-set position, redo re-applies the set.

Partially reverts 18334a4a0c ; ExtmarkSavePos.row/col were unused
because nothing recorded an explicit move, but now `extmark_set()` does.
This commit is contained in:
Justin M. Keyes
2026-08-10 04:21:31 -04:00
committed by GitHub
parent 8d406ed2ac
commit 2546741d1b
3 changed files with 51 additions and 7 deletions

View File

@@ -983,6 +983,25 @@ describe('API/extmarks', function()
eq(2, #rv)
end)
it('undo and redo of a mark explicitly moved during an edit', function()
feed('ggdGiabcdef<esc>')
set_extmark(ns, marks[1], 0, 4)
-- Insert at col 0; while the undo block is still open, explicitly
-- move the mark.
feed('0i!!')
set_extmark(ns, marks[1], 0, 1)
feed('<esc>')
eq({ 0, 1 }, get_extmark_by_id(ns, marks[1]))
feed('u')
-- Back where it was before the edit (the recorded set-time position,
-- shifted back by the splice reversal).
eq({ 0, 4 }, get_extmark_by_id(ns, marks[1]))
feed('<c-r>')
-- Redo restores the explicit position: splice adjustment alone would
-- leave the mark at col 6.
eq({ 0, 1 }, get_extmark_by_id(ns, marks[1]))
end)
it('undo and redo of marks deleted during edits', function()
-- test extmark_adjust
feed('A<cr>12345<esc>')