]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0384: stale Insstart after <Cmd> cursor move breaks undo v9.2.0384
authorJaehwang Jung <tomtomjhj@gmail.com>
Tue, 21 Apr 2026 19:21:24 +0000 (19:21 +0000)
committerChristian Brabandt <cb@256bit.org>
Tue, 21 Apr 2026 19:24:14 +0000 (19:24 +0000)
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: #20031

AI-assisted: Codex

Signed-off-by: Jaehwang Jung <tomtomjhj@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/edit.c
src/testdir/test_undo.vim
src/version.c

index 60cae0e15cc627f3bfaeda40cedc5a54aa5f137e..f15cc55f32f05ba758561688c39fc7025dadeb67 100644 (file)
@@ -2502,7 +2502,12 @@ stop_arrow(void)
     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(ml_get_curline());
            ins_need_undo = FALSE;
+       }
     }
 
 #ifdef FEAT_FOLDING
index ad724aa04d01c5e1672bc4a084b709276c93b843..97b77f423d1f42b3aac6f996bb4ff827fdf16dca 100644 (file)
@@ -924,5 +924,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
index 895c22e9c0a4a5b8b9c9d04fd8e01e457d264dd3..2a8b84404fb304ac0be6b3674adf5792b0e9c1de 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    384,
 /**/
     383,
 /**/