diff options
| author | zeertzjq <zeertzjq@outlook.com> | 2026-04-22 09:35:47 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-22 01:35:47 +0000 |
| commit | 2445fab6fb8c9b4d372ba7c02ff9fd1a2db6e4a4 (patch) | |
| tree | 53085ac753fee3da191a602dccd3a228f4d6e311 | |
| parent | 8efe4f9ac1b721267f886d6d577766cdbd2f7920 (diff) | |
vim-patch:9.2.0384: stale Insstart after cursor move breaks undo (#39290)
vim-patch:9.2.0384: stale Insstart after <Cmd> cursor move breaks undo
Problem: A <Cmd> command executed from Insert mode can sync undo and
move the cursor before the next edit. stop_arrow() saved the
new cursor line for undo, but left Insstart at the previous
insertion point. A line-start backspace could then delete
lines above the saved line without saving the joined range,
leaving a pending undo entry whose bottom resolved above
its top and raising E340.
Solution: Update Insstart and Insstart_textlen after the pending undo
save so the next edit starts from the command-updated cursor
position (Jaehwang Jung).
closes: vim/vim#20031
AI-assisted: Codex
https://github.com/vim/vim/commit/d4fb31762ea0b9de6fffb529c4ffee509621f74c
Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
| -rw-r--r-- | src/nvim/edit.c | 3 | ||||
| -rw-r--r-- | test/old/testdir/test_undo.vim | 14 |
2 files changed, 17 insertions, 0 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 15c0836cbe..d51929583e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2206,6 +2206,9 @@ int stop_arrow(void) new_insert_skip = 2; } else if (ins_need_undo) { if (u_save_cursor() == OK) { + // A command or event may have moved the cursor after syncing undo. + Insstart = curwin->w_cursor; + Insstart_textlen = (colnr_T)linetabsize_str(get_cursor_line_ptr()); ins_need_undo = false; } } diff --git a/test/old/testdir/test_undo.vim b/test/old/testdir/test_undo.vim index fe3d5f8209..0cf2ca4b37 100644 --- a/test/old/testdir/test_undo.vim +++ b/test/old/testdir/test_undo.vim @@ -923,5 +923,19 @@ func Test_restore_cursor_position_after_undo() bw! endfunc +func Test_undo_line_backspace_after_insert_cmd_cursor_movement() + new + setlocal backspace=eol undolevels=100 + call setline(1, ['', '', 'abc', 'def']) + call cursor(4, 1) + + let v:errmsg = '' + call feedkeys("i\<Cmd>setlocal undolevels=101 | call cursor(3, 1)\<CR>" + \ .. "\<BS>\<BS>\<Esc>u", 'xt') + + call assert_equal('', v:errmsg) + call assert_equal(['', '', 'abc', 'def'], getline(1, '$')) + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab |
