]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0510: setline() mapping may trigger autoindent v9.2.0510
authorglepnir <glephunter@gmail.com>
Fri, 22 May 2026 17:59:23 +0000 (17:59 +0000)
committerChristian Brabandt <cb@256bit.org>
Fri, 22 May 2026 17:59:23 +0000 (17:59 +0000)
Problem:  setline() insert mode mapping may trigger autoindent,
          corrupting the newly inserted line content (Evgeni Chasnovski)
Solution: Only strip autoindent whitespace when the rest of the line is
          all whitespace (glepnir).

fixes:  #19363
closes: #20290

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/edit.c
src/testdir/test_edit.vim
src/version.c

index 1db9c130717c36c1e14565c5c6a8abaa5c551856..512c0b23c4e609fdaf666c03f5a3613b8402ed7a 100644 (file)
@@ -2613,34 +2613,45 @@ stop_insert(
        {
            pos_T       tpos = curwin->w_cursor;
            colnr_T     prev_col = end_insert_pos->col;
+           colnr_T     strip_col;
 
            curwin->w_cursor = *end_insert_pos;
            check_cursor_col();  // make sure it is not past the line
-           for (;;)
-           {
-               if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
-                   --curwin->w_cursor.col;
-               cc = gchar_cursor();
-               if (!VIM_ISWHITE(cc))
-                   break;
-               if (del_char(TRUE) == FAIL)
-                   break;  // should not happen
-           }
-           if (curwin->w_cursor.lnum != tpos.lnum)
-               curwin->w_cursor = tpos;
-           else if (curwin->w_cursor.col < prev_col)
+
+           // Where the loop would actually start (back up if on NUL).
+           strip_col = curwin->w_cursor.col;
+           if (gchar_cursor() == NUL && strip_col > 0)
+               --strip_col;
+
+           // Don't strip if non-whitespace follows: setline() from a <Cmd>
+           // mapping or CursorHoldI autocmd may have inserted content.
+           if (*skipwhite(ml_get_curline() + strip_col) == NUL)
            {
-               // reset tpos, could have been invalidated in the loop above
-               tpos = curwin->w_cursor;
-               tpos.col++;
-               if (cc != NUL && gchar_pos(&tpos) == NUL)
-                   ++curwin->w_cursor.col;     // put cursor back on the NUL
-           }
+               curwin->w_cursor.col = strip_col;
+               for (;;)
+               {
+                   cc = gchar_cursor();
+                   if (!VIM_ISWHITE(cc))
+                       break;
+                   if (del_char(TRUE) == FAIL)
+                       break;  // should not happen
+               }
+               if (curwin->w_cursor.lnum != tpos.lnum)
+                   curwin->w_cursor = tpos;
+               else if (curwin->w_cursor.col < prev_col)
+               {
+                   // reset tpos, could have been invalidated in the loop above
+                   tpos = curwin->w_cursor;
+                   tpos.col++;
+                   if (cc != NUL && gchar_pos(&tpos) == NUL)
+                       ++curwin->w_cursor.col; // put cursor back on the NUL
+               }
 
-           // <C-S-Right> may have started Visual mode, adjust the position for
-           // deleted characters.
-           if (VIsual_active)
-               check_visual_pos();
+               // <C-S-Right> may have started Visual mode, adjust the position for
+               // deleted characters.
+               if (VIsual_active)
+                   check_visual_pos();
+           }
        }
     }
     did_ai = FALSE;
index 196933f7d93d3a1b87dc718108d47c8862d9b282..6511e178cff4da89d662083ce8e45c013fc812ef 100644 (file)
@@ -2458,4 +2458,28 @@ func Test_edit_CAR_with_completion()
   bw!
 endfunc
 
+func Test_autoindent_no_strip_after_cmd_setline()
+  new
+  setlocal autoindent
+  inoremap <buffer> <F2> <Cmd>call setline('.', 'v  v')<CR><Cmd>call cursor(line('.'), 2)<CR>
+  call feedkeys("Go\<F2>\<Esc>", 'tx')
+  call assert_equal('v  v', getline(2))
+  bwipe!
+endfunc
+
+func Test_autoindent_no_strip_after_cursorholdi()
+  CheckFeature timers
+  new
+  setlocal autoindent
+  set updatetime=50
+  au CursorHoldI <buffer> call setline('.', 'v v')
+  call setline(1, ' x')
+  call cursor(1, 2)
+  call timer_start(120, {-> feedkeys("\<Esc>", 't')})
+  call feedkeys("o", 'tx!')
+  call assert_equal('v v', getline(2))
+  set updatetime&
+  bwipe!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 7b80b546f37a253baf78c367222d6fc1682828e4..7b6e33045e95f73e7412f071e9756ce9378783c1 100644 (file)
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    510,
 /**/
     509,
 /**/