From 2445fab6fb8c9b4d372ba7c02ff9fd1a2db6e4a4 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 22 Apr 2026 09:35:47 +0800 Subject: [PATCH] vim-patch:9.2.0384: stale Insstart after cursor move breaks undo (#39290) vim-patch:9.2.0384: stale Insstart after cursor move breaks undo Problem: A 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 --- src/nvim/edit.c | 3 +++ test/old/testdir/test_undo.vim | 14 ++++++++++++++ 2 files changed, 17 insertions(+) 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\setlocal undolevels=101 | call cursor(3, 1)\" + \ .. "\\\u", 'xt') + + call assert_equal('', v:errmsg) + call assert_equal(['', '', 'abc', 'def'], getline(1, '$')) + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab