mirror of
https://github.com/neovim/neovim.git
synced 2026-05-23 21:30:11 +00:00
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:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2474,4 +2474,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
|
||||
|
||||
Reference in New Issue
Block a user