]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.1725: cursor pos wrong after concealed text with 'virtualedit' v9.0.1725
authorzeertzjq <zeertzjq@outlook.com>
Thu, 17 Aug 2023 20:35:26 +0000 (22:35 +0200)
committerChristian Brabandt <cb@256bit.org>
Thu, 17 Aug 2023 20:35:26 +0000 (22:35 +0200)
Problem:    Wrong cursor position when clicking after concealed text
            with 'virtualedit'.
Solution:   Store virtual columns in ScreenCols[] instead of text
            columns, and always use coladvance() when clicking.

This also fixes incorrect curswant when clicking on a TAB, so now
Test_normal_click_on_ctrl_char() asserts the same results as the ones
before patch 9.0.0048.

closes: #12808

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
src/drawline.c
src/globals.h
src/mouse.c
src/testdir/test_conceal.vim
src/testdir/test_normal.vim
src/testdir/test_virtualedit.vim
src/version.c

index ef9f6637155f6ec9d89db3eb9f52e19562395f3d..18ae4bf768a61df16635a6a3b71dccdd201931de 100644 (file)
@@ -1829,7 +1829,6 @@ win_line(
 
     win_line_start(wp, &wlv, FALSE);
 
-    char_u     *prev_ptr = ptr;
     // Repeat for the whole displayed line.
     for (;;)
     {
@@ -2261,9 +2260,9 @@ win_line(
            }
 #endif
 
+#ifdef FEAT_SEARCH_EXTRA
            if (wlv.n_extra == 0)
            {
-#ifdef FEAT_SEARCH_EXTRA
                // Check for start/end of 'hlsearch' and other matches.
                // After end, check for start/end of next match.
                // When another match, have to check for start again.
@@ -2278,10 +2277,8 @@ win_line(
                // and bad things happen.
                if (*ptr == NUL)
                    has_match_conc = 0;
-#endif
-
-               prev_ptr = ptr;
            }
+#endif
 
 #ifdef FEAT_DIFF
            if (wlv.diff_hlf != (hlf_T)0)
@@ -2356,7 +2353,6 @@ win_line(
                    // have made it invalid.
                    line = ml_get_buf(wp->w_buffer, lnum, FALSE);
                    ptr = line + v;
-                   prev_ptr = ptr;
 # ifdef FEAT_CONCEAL
                    // no concealing past the end of the line, it interferes
                    // with line highlighting
@@ -2567,7 +2563,9 @@ win_line(
 #ifdef FEAT_LINEBREAK
            int         c0;
 #endif
-           prev_ptr = ptr;
+#ifdef FEAT_SPELL
+           char_u      *prev_ptr = ptr;
+#endif
 
            // Get a character from the line itself.
            c = *ptr;
@@ -3809,7 +3807,7 @@ win_line(
            else
                ScreenAttrs[wlv.off] = wlv.char_attr;
 
-           ScreenCols[wlv.off] = (colnr_T)(prev_ptr - line);
+           ScreenCols[wlv.off] = wlv.vcol;
 
            if (has_mbyte && (*mb_char2cells)(mb_c) > 1)
            {
@@ -3833,7 +3831,7 @@ win_line(
                if (wlv.tocol == wlv.vcol)
                    ++wlv.tocol;
 
-               ScreenCols[wlv.off] = (colnr_T)(prev_ptr - line);
+               ScreenCols[wlv.off] = wlv.vcol;
 
 #ifdef FEAT_RIGHTLEFT
                if (wp->w_p_rl)
index 6a68c3acbb8f6f56e2a872fa2bad8fa825facf5e..c1e2d6fbc42c2c644ba94c52f1c6ef744d4d17fb 100644 (file)
@@ -32,7 +32,7 @@ EXTERN long   Columns INIT(= 80);     // nr of columns in the screen
  * The characters that are currently on the screen are kept in ScreenLines[].
  * It is a single block of characters, the size of the screen plus one line.
  * The attributes for those characters are kept in ScreenAttrs[].
- * The byte offset in the line is kept in ScreenCols[].
+ * The virtual column in the line is kept in ScreenCols[].
  *
  * "LineOffset[n]" is the offset from ScreenLines[] for the start of line 'n'.
  * The same value is used for ScreenLinesUC[], ScreenAttrs[] and ScreenCols[].
index 4e8dd4d230d7b71459c86985d967bfa6a21c57da..c9e96c9cab33803c32423b16d8c5b11b5bebe387 100644 (file)
@@ -2060,7 +2060,7 @@ retnomove:
        // Only use ScreenCols[] after the window was redrawn.  Mainly matters
        // for tests, a user would not click before redrawing.
        // Do not use when 'virtualedit' is active.
-       if (curwin->w_redr_type <= UPD_VALID_NO_UPDATE && !virtual_active())
+       if (curwin->w_redr_type <= UPD_VALID_NO_UPDATE)
            col_from_screen = ScreenCols[off];
 #ifdef FEAT_FOLDING
        // Remember the character under the mouse, it might be a '-' or '+' in
@@ -2098,40 +2098,46 @@ retnomove:
            redraw_cmdline = TRUE;      // show visual mode later
     }
 
-    if (col_from_screen >= 0)
+    if (col_from_screen == MAXCOL)
     {
-       // Use the column from ScreenCols[], it is accurate also after
-       // concealed characters.
-       curwin->w_cursor.col = col_from_screen;
-       if (col_from_screen == MAXCOL)
+       // When clicking after end of line, still need to set correct curswant
+       int off_l = LineOffset[prev_row];
+       if (ScreenCols[off_l] < MAXCOL)
        {
-           curwin->w_curswant = col_from_screen;
-           curwin->w_set_curswant = FALSE;     // May still have been TRUE
-           mouse_past_eol = TRUE;
-           if (inclusive != NULL)
-               *inclusive = TRUE;
+           // Binary search to find last char in line
+           int off_r = off_l + prev_col;
+           int off_click = off_r;
+           while (off_l < off_r)
+           {
+               int off_m = (off_l + off_r + 1) / 2;
+               if (ScreenCols[off_m] < MAXCOL)
+                   off_l = off_m;
+               else
+                   off_r = off_m - 1;
+           }
+           col = ScreenCols[off_r] + (off_click - off_r);
        }
        else
-       {
-           curwin->w_set_curswant = TRUE;
-           if (inclusive != NULL)
-               *inclusive = FALSE;
-       }
-       check_cursor_col();
+           // Shouldn't normally happen
+           col = MAXCOL;
     }
-    else
+    else if (col_from_screen >= 0)
     {
-       curwin->w_curswant = col;
-       curwin->w_set_curswant = FALSE; // May still have been TRUE
-       if (coladvance(col) == FAIL)    // Mouse click beyond end of line
-       {
-           if (inclusive != NULL)
-               *inclusive = TRUE;
-           mouse_past_eol = TRUE;
-       }
-       else if (inclusive != NULL)
-           *inclusive = FALSE;
+       // Use the virtual column from ScreenCols[], it is accurate also after
+       // concealed characters.
+       col = col_from_screen;
+    }
+
+    curwin->w_curswant = col;
+    curwin->w_set_curswant = FALSE;    // May still have been TRUE
+    if (coladvance(col) == FAIL)       // Mouse click beyond end of line
+    {
+       if (inclusive != NULL)
+           *inclusive = TRUE;
+       mouse_past_eol = TRUE;
     }
+    else if (inclusive != NULL)
+       *inclusive = FALSE;
 
     count = IN_BUFFER;
     if (curwin != old_curwin || curwin->w_cursor.lnum != old_cursor.lnum
index d9a76441186a23b7ac8fb28cafa996ed351eef41..09b986f3396477d3912c577baa4a1c89feec9ae6 100644 (file)
@@ -351,9 +351,55 @@ func Test_conceal_mouse_click()
   call test_setmouse(1, 16)
   call feedkeys("\<LeftMouse>", "tx")
   call assert_equal([0, 1, 20, 0, 20], getcurpos())
+  " click on 'e' of "here" puts cursor there
+  call test_setmouse(1, 19)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 23], getcurpos())
+  " click after end of line puts cursor on 'e' without 'virtualedit'
+  call test_setmouse(1, 20)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 24], getcurpos())
+  call test_setmouse(1, 21)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 25], getcurpos())
+  call test_setmouse(1, 22)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 26], getcurpos())
+  call test_setmouse(1, 31)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 35], getcurpos())
+  call test_setmouse(1, 32)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 36], getcurpos())
+
+  set virtualedit=all
+  " click on 'h' of "here" puts cursor there
+  call test_setmouse(1, 16)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 20, 0, 20], getcurpos())
+  " click on 'e' of "here" puts cursor there
+  call test_setmouse(1, 19)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 23, 0, 23], getcurpos())
+  " click after end of line puts cursor there without 'virtualedit'
+  call test_setmouse(1, 20)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 24, 0, 24], getcurpos())
+  call test_setmouse(1, 21)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 24, 1, 25], getcurpos())
+  call test_setmouse(1, 22)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 24, 2, 26], getcurpos())
+  call test_setmouse(1, 31)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 24, 11, 35], getcurpos())
+  call test_setmouse(1, 32)
+  call feedkeys("\<LeftMouse>", "tx")
+  call assert_equal([0, 1, 24, 12, 36], getcurpos())
 
   bwipe!
-  set mouse&
+  set mouse& virtualedit&
 endfunc
 
 " vim: shiftwidth=2 sts=2 expandtab
index c4d6ef6dde7a234123bede10172929dae3aef57c..e9478fab7697b8ebcc22c7cbbc926364daf28bbb 100644 (file)
@@ -4049,13 +4049,13 @@ func Test_normal_click_on_ctrl_char()
   call assert_equal([0, 1, 1, 0, 1], getcurpos())
   call test_setmouse(1, 2)
   call feedkeys("\<LeftMouse>", 'xt')
-  call assert_equal([0, 1, 2, 0, 8], getcurpos())
+  call assert_equal([0, 1, 2, 0, 2], getcurpos())
   call test_setmouse(1, 3)
   call feedkeys("\<LeftMouse>", 'xt')
-  call assert_equal([0, 1, 2, 0, 8], getcurpos())
+  call assert_equal([0, 1, 2, 0, 3], getcurpos())
   call test_setmouse(1, 7)
   call feedkeys("\<LeftMouse>", 'xt')
-  call assert_equal([0, 1, 2, 0, 8], getcurpos())
+  call assert_equal([0, 1, 2, 0, 7], getcurpos())
   call test_setmouse(1, 8)
   call feedkeys("\<LeftMouse>", 'xt')
   call assert_equal([0, 1, 2, 0, 8], getcurpos())
@@ -4067,13 +4067,13 @@ func Test_normal_click_on_ctrl_char()
   call assert_equal([0, 1, 4, 0, 10], getcurpos())
   call test_setmouse(1, 11)
   call feedkeys("\<LeftMouse>", 'xt')
-  call assert_equal([0, 1, 4, 0, 10], getcurpos())
+  call assert_equal([0, 1, 4, 0, 11], getcurpos())
   call test_setmouse(1, 12)
   call feedkeys("\<LeftMouse>", 'xt')
   call assert_equal([0, 1, 5, 0, 12], getcurpos())
   call test_setmouse(1, 13)
   call feedkeys("\<LeftMouse>", 'xt')
-  call assert_equal([0, 1, 5, 0, v:maxcol], getcurpos())
+  call assert_equal([0, 1, 5, 0, 13], getcurpos())
 
   bwipe!
   let &mouse = save_mouse
index edaae678609dd5ec158ea710eb29c5e8eca177f1..da5f6f5c382a1100efa133a479cbdc7e911e6f65 100644 (file)
@@ -586,6 +586,12 @@ func Test_virtualedit_mouse()
   call test_setmouse(1, 9)
   call feedkeys("\<LeftMouse>", "xt")
   call assert_equal([0, 1, 6, 0, 9], getcurpos())
+  call test_setmouse(1, 12)
+  call feedkeys("\<LeftMouse>", "xt")
+  call assert_equal([0, 1, 9, 0, 12], getcurpos())
+  call test_setmouse(1, 13)
+  call feedkeys("\<LeftMouse>", "xt")
+  call assert_equal([0, 1, 10, 0, 13], getcurpos())
   call test_setmouse(1, 15)
   call feedkeys("\<LeftMouse>", "xt")
   call assert_equal([0, 1, 10, 2, 15], getcurpos())
index 0d898692b2fc58327cb80aeba2ff82113d075e86..36b1a6ad545645f0d8ae573e1358ef5418c40944 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1725,
 /**/
     1724,
 /**/