]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2022: getmousepos() returns wrong index for TAB char v9.0.2022
authorzeertzjq <zeertzjq@outlook.com>
Sat, 14 Oct 2023 09:32:28 +0000 (11:32 +0200)
committerChristian Brabandt <cb@256bit.org>
Sat, 14 Oct 2023 09:32:28 +0000 (11:32 +0200)
Problem:  When clicking in the middle of a TAB, getmousepos() returns
          the column of the next char instead of the TAB.
Solution: Break out of the loop when the vcol to find is inside current
          char. Fix invalid memory access when calling virtcol2col() on
          an empty line.

closes: #13321

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
runtime/doc/builtin.txt
src/mouse.c
src/move.c
src/testdir/test_cursor_func.vim
src/testdir/test_functions.vim
src/version.c

index 029c08bbd94d9895786142e498252e43eeb381eb..f621fc05162b1504c6ef56f9950a8e94c3674883 100644 (file)
@@ -10376,6 +10376,8 @@ virtcol2col({winid}, {lnum}, {col})                     *virtcol2col()*
                character in window {winid} at buffer line {lnum} and virtual
                column {col}.
 
+               If buffer line {lnum} is an empty line, 0 is returned.
+
                If {col} is greater than the last virtual column in line
                {lnum}, then the byte index of the character at the last
                virtual column is returned.
index f3342f905699091f8c14ff8f0df873b466542b93..fe5c14cac57e27c17ddfa1e3e93231bb174f4af6 100644 (file)
@@ -3201,7 +3201,7 @@ mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
        || defined(FEAT_EVAL) || defined(PROTO)
 /*
  * Convert a virtual (screen) column to a character column.
- * The first column is one.
+ * The first column is zero.
  */
     int
 vcol2col(win_T *wp, linenr_T lnum, int vcol)
@@ -3214,7 +3214,10 @@ vcol2col(win_T *wp, linenr_T lnum, int vcol)
     init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
     while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL)
     {
-       cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
+       int size = win_lbr_chartabsize(&cts, NULL);
+       if (cts.cts_vcol + size > vcol)
+           break;
+       cts.cts_vcol += size;
        MB_PTR_ADV(cts.cts_ptr);
     }
     clear_chartabsize_arg(&cts);
index 42878e4ad9c2879a2a417434c86290ccf7a9067c..72490d2f854278b2c01e656de504219990fe27bf 100644 (file)
@@ -1547,14 +1547,17 @@ f_screenpos(typval_T *argvars UNUSED, typval_T *rettv)
     static int
 virtcol2col(win_T *wp, linenr_T lnum, int vcol)
 {
-    int                offset = vcol2col(wp, lnum, vcol);
+    int                offset = vcol2col(wp, lnum, vcol - 1);
     char_u     *line = ml_get_buf(wp->w_buffer, lnum, FALSE);
     char_u     *p = line + offset;
 
-    // For a multibyte character, need to return the column number of the first
-    // byte.
-    MB_PTR_BACK(line, p);
-
+    if (*p == NUL)
+    {
+       if (p == line)  // empty line
+           return 0;
+       // Move to the first byte of the last char.
+       MB_PTR_BACK(line, p);
+    }
     return (int)(p - line + 1);
 }
 
index 4fc59288c0fe564201d23d4ae6280e9348cb7cc6..3cdf4cb7f946428f0320327063a3ac9b43daa0e7 100644 (file)
@@ -573,6 +573,11 @@ func Test_virtcol2col()
   call assert_equal(8, virtcol2col(0, 1, 7))
   call assert_equal(8, virtcol2col(0, 1, 8))
 
+  " These used to cause invalid memory access
+  call setline(1, '')
+  call assert_equal(0, virtcol2col(0, 1, 1))
+  call assert_equal(0, virtcol2col(0, 1, 2))
+
   let w = winwidth(0)
   call setline(2, repeat('a', w + 2))
   let win_nosbr = win_getid()
index bf0bf9036dc17a77c123d3088ae2cc46399a9406..50b7fb23cae6b69c63a74b2d75813cb2363330fe 100644 (file)
@@ -3366,6 +3366,46 @@ func Test_getmousepos()
         \ line: 1,
         \ column: 1,
         \ }, getmousepos())
+  call test_setmouse(1, 2)
+  call assert_equal(#{
+        \ screenrow: 1,
+        \ screencol: 2,
+        \ winid: win_getid(),
+        \ winrow: 1,
+        \ wincol: 2,
+        \ line: 1,
+        \ column: 1,
+        \ }, getmousepos())
+  call test_setmouse(1, 8)
+  call assert_equal(#{
+        \ screenrow: 1,
+        \ screencol: 8,
+        \ winid: win_getid(),
+        \ winrow: 1,
+        \ wincol: 8,
+        \ line: 1,
+        \ column: 1,
+        \ }, getmousepos())
+  call test_setmouse(1, 9)
+  call assert_equal(#{
+        \ screenrow: 1,
+        \ screencol: 9,
+        \ winid: win_getid(),
+        \ winrow: 1,
+        \ wincol: 9,
+        \ line: 1,
+        \ column: 2,
+        \ }, getmousepos())
+  call test_setmouse(1, 12)
+  call assert_equal(#{
+        \ screenrow: 1,
+        \ screencol: 12,
+        \ winid: win_getid(),
+        \ winrow: 1,
+        \ wincol: 12,
+        \ line: 1,
+        \ column: 2,
+        \ }, getmousepos())
   call test_setmouse(1, 25)
   call assert_equal(#{
         \ screenrow: 1,
index 2c9354634b597dff3a6204af26e61db9b655541c..d842108880aabe4e25b4bc70e3983ac581f5fb13 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2022,
 /**/
     2021,
 /**/