neovim

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

commit 68a54bfda65f5ddb9b96001ab22c55e71eeb45ef
parent 86d90f3fff9e3aca6999b42813da66987daafc86
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Sat, 18 Oct 2025 23:14:20 +0800

vim-patch:9.1.1868: v:register is wrong in v_: command (#36238)

Problem:  v:register is wrong in v_: command (after 9.1.1858).
Solution: Don't reset v:register for OP_COLON (zeertzjq)

related: https://github.com/vim/vim/pull/18583#issuecomment-3418030021

closes: vim/vim#18597

https://github.com/vim/vim/commit/0124320c97b0fbbb44613f42fc1c34fee6181fc8

While at it, also fix using stale set_prevcount value. That only matters
when readbuf1 ends with an operator or a register, which never happens,
but it's still good to avoid using a stale value.
Diffstat:
Msrc/nvim/normal.c | 11++++++++---
Mtest/old/testdir/test_registers.vim | 28++++++++++++++++++++++++++++
2 files changed, 36 insertions(+), 3 deletions(-)

diff --git a/src/nvim/normal.c b/src/nvim/normal.c @@ -544,6 +544,7 @@ static void normal_prepare(NormalState *s) } may_trigger_modechanged(); + s->set_prevcount = false; // When not finishing an operator and no register name typed, reset the count. if (!finish_op && !s->oa.regname) { s->ca.opcount = 0; @@ -964,6 +965,8 @@ static bool normal_get_command_count(NormalState *s) static void normal_finish_command(NormalState *s) { + bool did_visual_op = false; + if (s->command_finished) { goto normal_end; } @@ -983,11 +986,13 @@ static void normal_finish_command(NormalState *s) s->old_mapped_len = typebuf_maplen(); } - const bool prev_VIsual_active = VIsual_active; - // If an operation is pending, handle it. But not for K_IGNORE or // K_MOUSEMOVE. if (s->ca.cmdchar != K_IGNORE && s->ca.cmdchar != K_MOUSEMOVE) { + did_visual_op = VIsual_active && s->oa.op_type != OP_NOP + // For OP_COLON, do_pending_operator() stuffs ':' into + // the read buffer, which isn't executed immediately. + && s->oa.op_type != OP_COLON; do_pending_operator(&s->ca, s->old_col, false); } @@ -1002,7 +1007,7 @@ normal_end: msg_nowait = false; - if (finish_op || prev_VIsual_active) { + if (finish_op || did_visual_op) { set_reg_var(get_default_register_name()); } diff --git a/test/old/testdir/test_registers.vim b/test/old/testdir/test_registers.vim @@ -671,7 +671,9 @@ func Test_v_register() exec 'normal! "' .. v:register .. 'P' endfunc nnoremap <buffer> <plug>(test) :<c-u>call s:Put()<cr> + xnoremap <buffer> <plug>(test) :<c-u>call s:Put()<cr> nmap <buffer> S <plug>(test) + xmap <buffer> S <plug>(test) let @z = "testz\n" let @" = "test@\n" @@ -689,16 +691,42 @@ func Test_v_register() let s:register = '' call feedkeys('"zS', 'mx') call assert_equal('z', s:register) + call assert_equal('testz', getline('.')) let s:register = '' call feedkeys('"zSS', 'mx') call assert_equal('"', s:register) + call assert_equal('test@', getline('.')) + + let s:register = '' + call feedkeys("\"z\<Ignore>S", 'mx') + call assert_equal('z', s:register) + call assert_equal('testz', getline('.')) let s:register = '' call feedkeys('"_S', 'mx') call assert_equal('_', s:register) let s:register = '' + call feedkeys('V"zS', 'mx') + call assert_equal('z', s:register) + call assert_equal('testz', getline('.')) + + let s:register = '' + call feedkeys('V"zSS', 'mx') + call assert_equal('"', s:register) + call assert_equal('test@', getline('.')) + + let s:register = '' + call feedkeys("V\"z\<Ignore>S", 'mx') + call assert_equal('z', s:register) + call assert_equal('testz', getline('.')) + + let s:register = '' + call feedkeys('V"_S', 'mx') + call assert_equal('_', s:register) + + let s:register = '' normal "_ddS call assert_equal('"', s:register) " fails before 8.2.0929 call assert_equal('test@', getline('.')) " fails before 8.2.0929