Commit: patch 9.1.1175: inconsistent behaviour with exclusive selection and motion commands

1 view
Skip to first unread message

Christian Brabandt

unread,
Mar 5, 2025, 3:00:11 PM3/5/25
to vim...@googlegroups.com
patch 9.1.1175: inconsistent behaviour with exclusive selection and motion commands

Commit: https://github.com/vim/vim/commit/c8cce711dde2d8abcf0929b3b12c4bfc5547a89d
Author: Jim Zhou <jimzh...@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.eas...@gmail.com>
Co-authored-by: zeertzjq <zeer...@outlook.com>
Signed-off-by: Jim Zhou <jimzh...@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,
/**/
Reply all
Reply to author
Forward
0 new messages