summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2026-04-22 09:35:47 +0800
committerGitHub <noreply@github.com>2026-04-22 01:35:47 +0000
commit2445fab6fb8c9b4d372ba7c02ff9fd1a2db6e4a4 (patch)
tree53085ac753fee3da191a602dccd3a228f4d6e311
parent8efe4f9ac1b721267f886d6d577766cdbd2f7920 (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.c3
-rw-r--r--test/old/testdir/test_undo.vim14
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