patch 9.1.1175: inconsistent behaviour with exclusive selection and motion commands
Commit: https://github.com/vim/vim/commit/c8cce711dde2d8abcf0929b3b12c4bfc5547a89d Author: Jim Zhou <jimzhou...@gmail.com> Date: Wed Mar 5 20:47:29 2025 +0100 patch 9.1.1175: inconsistent behaviour with exclusive selection and motion commands Problem: inconsistent behaviour with exclusive selection and motion commands (aidancz) Solution: adjust cursor position when selection is exclusive (Jim Zhou) fixes: #16278 closes: #16784 Co-authored-by: Hirohito Higashi <h.east....@gmail.com> Co-authored-by: zeertzjq <zeert...@outlook.com> Signed-off-by: Jim Zhou <jimzhou...@gmail.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/src/globals.h b/src/globals.h index 3827c1a2e..ef78b4433 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1144,6 +1144,8 @@ EXTERN int VIsual_select INIT(= FALSE); // whether Select mode is active EXTERN int VIsual_select_reg INIT(= 0); // register name for Select mode +EXTERN int VIsual_select_exclu_adj INIT(= FALSE); + // whether incremented cursor during exclusive selection EXTERN int restart_VIsual_select INIT(= 0); // restart Select mode when next cmd finished EXTERN int VIsual_reselect; diff --git a/src/normal.c b/src/normal.c index 1189737c3..e7915d6ff 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1130,6 +1130,7 @@ call_yank_do_autocmd(int regname) void end_visual_mode(void) { + VIsual_select_exclu_adj = FALSE; end_visual_mode_keep_button(); reset_held_button(); } @@ -4248,6 +4249,15 @@ normal_search( nv_csearch(cmdarg_T *cap) { int t_cmd; + int cursor_dec = FALSE; + + // If adjusted cursor position previously, unadjust it. + if (*p_sel == 'e' && VIsual_active && VIsual_mode == 'v' + && VIsual_select_exclu_adj) + { + unadjust_for_sel(); + cursor_dec = TRUE; + } if (cap->cmdchar == 't' || cap->cmdchar == 'T') t_cmd = TRUE; @@ -4258,6 +4268,9 @@ nv_csearch(cmdarg_T *cap) if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == FAIL) { clearopbeep(cap->oap); + // Revert unadjust when failed. + if (cursor_dec) + adjust_for_sel(cap); return; } @@ -5534,6 +5547,8 @@ nv_visual(cmdarg_T *cap) n_start_visual_mode(cap->cmdchar); if (VIsual_mode != 'V' && *p_sel == 'e') ++cap->count1; // include one more char + else + VIsual_select_exclu_adj = FALSE; if (cap->count0 > 0 && --cap->count1 > 0) { // With a count select that many characters or lines. @@ -6703,6 +6718,7 @@ adjust_for_sel(cmdarg_T *cap) else ++curwin->w_cursor.col; cap->oap->inclusive = FALSE; + VIsual_select_exclu_adj = TRUE; } } @@ -6728,6 +6744,7 @@ unadjust_for_sel(void) unadjust_for_sel_inner(pos_T *pp) { colnr_T cs, ce; + VIsual_select_exclu_adj = FALSE; if (pp->coladd > 0) --pp->coladd; diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 6c2ef59f9..2665faa45 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1099,6 +1099,50 @@ func Test_exclusive_selection() bw! endfunc +" Test for inclusive motion in visual mode with 'exclusive' selection +func Test_inclusive_motion_selection_exclusive() + func s:compare_exclu_inclu(line, keys, expected_exclu) + let msg = "data: '" . a:line . "' operation: '" . a:keys . "'" + call setline(1, a:line) + set selection=exclusive + call feedkeys(a:keys, 'xt') + call assert_equal(a:expected_exclu, getpos('.'), msg) + let pos_ex = col('.') + set selection=inclusive + call feedkeys(a:keys, 'xt') + let pos_in = col('.') + call assert_equal(1, pos_ex - pos_in, msg) + endfunc + + new + " Test 'e' motion + set selection=exclusive + call setline(1, 'eins zwei drei') + norm! ggvey + call assert_equal('eins', @") + call setline(1, 'abc(abc)abc') + norm! ggveeed + call assert_equal(')abc', getline(1)) + call setline(1, 'abc(abc)abc') + norm! gg3lvey + call assert_equal('(abc', @") + call s:compare_exclu_inclu('abc(abc)abc', 'ggveee', [0, 1, 8, 0]) + " Test 'f' motion + call s:compare_exclu_inclu('geschwindigkeit', 'ggvfefe', [0, 1, 14, 0]) + call s:compare_exclu_inclu('loooooooooooong', 'ggv2fo2fo2fo', [0, 1, 8, 0]) + " Test 't' motion + call s:compare_exclu_inclu('geschwindigkeit', 'ggv2te', [0, 1, 13, 0]) + call s:compare_exclu_inclu('loooooooooooong', 'gglv2to2to2to', [0, 1, 6, 0]) + " Test ';' motion + call s:compare_exclu_inclu('geschwindigkeit', 'ggvfi;;', [0, 1, 15, 0]) + call s:compare_exclu_inclu('geschwindigkeit', 'ggvti;;', [0, 1, 14, 0]) + call s:compare_exclu_inclu('loooooooooooong', 'ggv2fo;;', [0, 1, 6, 0]) + call s:compare_exclu_inclu('loooooooooooong', 'ggvl2to;;', [0, 1, 6, 0]) + " Clean up + set selection& + bw! +endfunc + " Test for starting linewise visual with a count. " This test needs to be run without any previous visual mode. Otherwise the " count will use the count from the previous visual mode. diff --git a/src/textobject.c b/src/textobject.c index aa2db0770..34d0c7657 100644 --- a/src/textobject.c +++ b/src/textobject.c @@ -502,6 +502,12 @@ end_word( curwin->w_cursor.coladd = 0; cls_bigword = bigword; + + // If adjusted cursor position previously, unadjust it. + if (*p_sel == 'e' && VIsual_active && VIsual_mode == 'v' + && VIsual_select_exclu_adj) + unadjust_for_sel(); + while (--count >= 0) { #ifdef FEAT_FOLDING diff --git a/src/version.c b/src/version.c index a8c22669d..6553fa4fd 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1175, /**/ 1174, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1tpuuR-00AbC7-7d%40256bit.org.