vim-patch:9.2.0510: setline() mapping may trigger autoindent (#39961)

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:  vim/vim#19363
closes: vim/vim#20290

e3dedac77b

Co-authored-by: glepnir <glephunter@gmail.com>
This commit is contained in:
zeertzjq
2026-05-23 08:57:36 +08:00
committed by GitHub
parent 7a1bad27ca
commit c8dbb04da9
2 changed files with 58 additions and 25 deletions

View File

@@ -2295,33 +2295,42 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove)
curwin->w_cursor = *end_insert_pos;
check_cursor_col(curwin); // make sure it is not past the line
while (true) {
if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) {
curwin->w_cursor.col--;
}
cc = gchar_cursor();
if (!ascii_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
}
// Where the loop would actually start (back up if NUL).
colnr_T strip_col = curwin->w_cursor.col;
if (gchar_cursor() == NUL && strip_col > 0) {
strip_col--;
}
// <C-S-Right> may have started Visual mode, adjust the position for
// deleted characters.
if (VIsual_active) {
check_visual_pos();
// Don't strip if non-whitespace follows: setline() from a <Cmd>
// mapping or CursorHoldI autocmd may have inserted content.
if (*skipwhite(get_cursor_line_ptr() + strip_col) == NUL) {
curwin->w_cursor.col = strip_col;
while (true) {
cc = gchar_cursor();
if (!ascii_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();
}
}
}
}