patch 9.2.0510: setline() mapping may trigger autoindent

Commit: 
https://github.com/vim/vim/commit/e3dedac77b2076210e7027b14a5927622434f014
Author: glepnir <[email protected]>
Date:   Fri May 22 17:59:23 2026 +0000

    patch 9.2.0510: setline() mapping may trigger autoindent
    
    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 <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/src/edit.c b/src/edit.c
index 1db9c1307..512c0b23c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -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;
diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim
index 196933f7d..6511e178c 100644
--- a/src/testdir/test_edit.vim
+++ b/src/testdir/test_edit.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 7b80b546f..7b6e33045 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    510,
 /**/
     509,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1wQUOm-000x5n-Dw%40256bit.org.

Raspunde prin e-mail lui