neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 430d12a4fdc99a5f593d459994675ac17fc7c89c
parent 4d83649d1022a8956660b4ae83c28998cabfcfca
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Wed, 19 Mar 2025 07:34:02 +0800

vim-patch:9.1.1221: Wrong cursor pos when leaving Insert mode just after 'autoindent' (#32976)

Problem:  Wrong cursor position and '^' mark when leaving Insert mode
          just after 'autoindent' and cursor on last char of line.
Solution: Don't move cursor to NUL when it wasn't moved to the left
          (zeertzjq).

fixes: vim/vim#15581
related: neovim/neovim#30165 neovim/neovim#32943
closes: vim/vim#16922

https://github.com/vim/vim/commit/a3a7d10bfb9547991e04bcf12d1391deb8060754
Diffstat:
Msrc/nvim/edit.c | 3++-
Mtest/old/testdir/test_edit.vim | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/src/nvim/edit.c b/src/nvim/edit.c @@ -2390,6 +2390,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) end_insert_pos->lnum)) && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count) { pos_T tpos = curwin->w_cursor; + colnr_T prev_col = end_insert_pos->col; curwin->w_cursor = *end_insert_pos; check_cursor_col(curwin); // make sure it is not past the line @@ -2407,7 +2408,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) } if (curwin->w_cursor.lnum != tpos.lnum) { curwin->w_cursor = tpos; - } else { + } else if (curwin->w_cursor.col < prev_col) { // reset tpos, could have been invalidated in the loop above tpos = curwin->w_cursor; tpos.col++; diff --git a/test/old/testdir/test_edit.vim b/test/old/testdir/test_edit.vim @@ -466,6 +466,64 @@ func Test_autoindent_remove_indent() call delete('Xarifile') endfunc +func Test_edit_esc_after_CR_autoindent() + new + setlocal autoindent + autocmd InsertLeavePre * let g:prev_cursor = getpos('.') + + call setline(1, 'foobar') + exe "normal! $hi\<CR>\<Esc>" + call assert_equal(['foob', 'ar'], getline(1, '$')) + call assert_equal([0, 2, 1, 0], getpos('.')) + call assert_equal([0, 2, 1, 0], getpos("'^")) + call assert_equal([0, 2, 1, 0], g:prev_cursor) + %d + + call setline(1, 'foobar') + exe "normal! $i\<CR>\<Esc>" + call assert_equal(['fooba', 'r'], getline(1, '$')) + call assert_equal([0, 2, 1, 0], getpos('.')) + call assert_equal([0, 2, 1, 0], getpos("'^")) + call assert_equal([0, 2, 1, 0], g:prev_cursor) + %d + + call setline(1, 'foobar') + exe "normal! A\<CR>\<Esc>" + call assert_equal(['foobar', ''], getline(1, '$')) + call assert_equal([0, 2, 1, 0], getpos('.')) + call assert_equal([0, 2, 1, 0], getpos("'^")) + call assert_equal([0, 2, 1, 0], g:prev_cursor) + %d + + call setline(1, ' foobar') + exe "normal! $hi\<CR>\<Esc>" + call assert_equal([' foob', ' ar'], getline(1, '$')) + call assert_equal([0, 2, 2, 0], getpos('.')) + call assert_equal([0, 2, 3, 0], getpos("'^")) + call assert_equal([0, 2, 3, 0], g:prev_cursor) + %d + + call setline(1, ' foobar') + exe "normal! $i\<CR>\<Esc>" + call assert_equal([' fooba', ' r'], getline(1, '$')) + call assert_equal([0, 2, 2, 0], getpos('.')) + call assert_equal([0, 2, 3, 0], getpos("'^")) + call assert_equal([0, 2, 3, 0], g:prev_cursor) + %d + + call setline(1, ' foobar') + exe "normal! A\<CR>\<Esc>" + call assert_equal([' foobar', ''], getline(1, '$')) + call assert_equal([0, 2, 1, 0], getpos('.')) + call assert_equal([0, 2, 1, 0], getpos("'^")) + call assert_equal([0, 2, 1, 0], g:prev_cursor) + %d + + autocmd! InsertLeavePre + unlet g:prev_cursor + bwipe! +endfunc + func Test_edit_CR() " Test for <CR> in insert mode " basically only in quickfix mode it's tested, the rest