]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1175: inconsistent behaviour with exclusive selection and motion commands v9.1.1175
authorJim Zhou <jimzhouzzy@gmail.com>
Wed, 5 Mar 2025 19:47:29 +0000 (20:47 +0100)
committerChristian Brabandt <cb@256bit.org>
Wed, 5 Mar 2025 19:47:29 +0000 (20:47 +0100)
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.727@gmail.com>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Jim Zhou <jimzhouzzy@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/globals.h
src/normal.c
src/testdir/test_visual.vim
src/textobject.c
src/version.c

index 3827c1a2e0d95f8cc9d237c40cb4d922bbb926d8..ef78b443399e38196edbae4e61c1ba374eefd9be 100644 (file)
@@ -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;
index 1189737c33b4ba8a6ef6fd124c052a7481d5b6b5..e7915d6ff88f23c604e31a995c96830f90405991 100644 (file)
@@ -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;
index 6c2ef59f9321eeec170f725e51d7991183cd75c5..2665faa451d7f34b5da792a2e9e2f5754662a7d4 100644 (file)
@@ -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.
index aa2db0770942d36c1e591114a8a4cb26a51d103b..34d0c76577d173032715ddb0bee9d95665aaee99 100644 (file)
@@ -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
index a8c22669db1ad7fbc757b0e890b4d6ecfd9ed7e8..6553fa4fdb518d20dab22817af62391d93392f5d 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1175,
 /**/
     1174,
 /**/