vim-patch:9.1.2019: inconsistent cursor encoding past EOL with ve=all

Problem:  When virtualedit is set to all, the cursor is supposed to be
          permitted to reside anywhere, including on the virtual space
          beyond the end of the buffer's text. Switching modes triggered
          a routine that "fixed" a cursor that was past the end of the
          line by shifting it back to the last actual character in the
          line and compensating with a virtual column offset. While
          visually identical, this re-encoding changed the underlying
          byte index, causing position-reporting functions to return
          inconsistent values after a mode change.
Solution: Skip this coordinate adjustment when virtual editing is fully
          enabled. By treating the line terminator as a valid, stable
          position, the cursor’s internal representation remains
          unchanged when entering or exiting Visual mode, ensuring
          consistent coordinate reporting. Add a regression test to
          check this functionality.
          (McAuley Penney)

fixes:  vim/vim#16276
closes: vim/vim#19009

491f0fa457

Co-authored-by: McAuley Penney <jacobmpenney@gmail.com>
This commit is contained in:
zeertzjq
2025-12-28 07:01:10 +08:00
parent 922816877f
commit e53accf8ec
2 changed files with 21 additions and 0 deletions

View File

@@ -1793,6 +1793,7 @@ void adjust_cursor_eol(void)
const bool adj_cursor = (curwin->w_cursor.col > 0
&& gchar_cursor() == NUL
&& (cur_ve_flags & kOptVeFlagOnemore) == 0
&& (cur_ve_flags & kOptVeFlagAll) == 0
&& !(restart_edit || (State & MODE_INSERT)));
if (!adj_cursor) {
return;

View File

@@ -732,4 +732,24 @@ func Test_virtualedit_set_cursor_pos_maxcol()
bwipe!
endfunc
" Verify that getpos() remains consistent when the cursor is past EOL after toggling Visual mode with virtualedit=all.
func Test_virtualedit_getpos_stable_past_eol_after_visual()
new
set virtualedit=all
call setline(1, 'abc')
normal! gg$3l
let p1 = getpos('.')
normal! v
redraw
normal! \<Esc>
let p2 = getpos('.')
call assert_equal(p1, p2, 'Position should not be re-encoded after leaving Visual mode')
set virtualedit&
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab