Skip to content

Commit b583eda

Browse files
zeertzjqchrisbra
authored andcommitted
patch 9.0.2022: getmousepos() returns wrong index for TAB char
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 <[email protected]> Co-authored-by: zeertzjq <[email protected]>
1 parent cd6ee69 commit b583eda

6 files changed

Lines changed: 62 additions & 7 deletions

File tree

runtime/doc/builtin.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10376,6 +10376,8 @@ virtcol2col({winid}, {lnum}, {col}) *virtcol2col()*
1037610376
character in window {winid} at buffer line {lnum} and virtual
1037710377
column {col}.
1037810378

10379+
If buffer line {lnum} is an empty line, 0 is returned.
10380+
1037910381
If {col} is greater than the last virtual column in line
1038010382
{lnum}, then the byte index of the character at the last
1038110383
virtual column is returned.

src/mouse.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3201,7 +3201,7 @@ mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
32013201
|| defined(FEAT_EVAL) || defined(PROTO)
32023202
/*
32033203
* Convert a virtual (screen) column to a character column.
3204-
* The first column is one.
3204+
* The first column is zero.
32053205
*/
32063206
int
32073207
vcol2col(win_T *wp, linenr_T lnum, int vcol)
@@ -3214,7 +3214,10 @@ vcol2col(win_T *wp, linenr_T lnum, int vcol)
32143214
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
32153215
while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL)
32163216
{
3217-
cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
3217+
int size = win_lbr_chartabsize(&cts, NULL);
3218+
if (cts.cts_vcol + size > vcol)
3219+
break;
3220+
cts.cts_vcol += size;
32183221
MB_PTR_ADV(cts.cts_ptr);
32193222
}
32203223
clear_chartabsize_arg(&cts);

src/move.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,14 +1547,17 @@ f_screenpos(typval_T *argvars UNUSED, typval_T *rettv)
15471547
static int
15481548
virtcol2col(win_T *wp, linenr_T lnum, int vcol)
15491549
{
1550-
int offset = vcol2col(wp, lnum, vcol);
1550+
int offset = vcol2col(wp, lnum, vcol - 1);
15511551
char_u *line = ml_get_buf(wp->w_buffer, lnum, FALSE);
15521552
char_u *p = line + offset;
15531553

1554-
// For a multibyte character, need to return the column number of the first
1555-
// byte.
1556-
MB_PTR_BACK(line, p);
1557-
1554+
if (*p == NUL)
1555+
{
1556+
if (p == line) // empty line
1557+
return 0;
1558+
// Move to the first byte of the last char.
1559+
MB_PTR_BACK(line, p);
1560+
}
15581561
return (int)(p - line + 1);
15591562
}
15601563

src/testdir/test_cursor_func.vim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,11 @@ func Test_virtcol2col()
573573
call assert_equal(8, virtcol2col(0, 1, 7))
574574
call assert_equal(8, virtcol2col(0, 1, 8))
575575

576+
" These used to cause invalid memory access
577+
call setline(1, '')
578+
call assert_equal(0, virtcol2col(0, 1, 1))
579+
call assert_equal(0, virtcol2col(0, 1, 2))
580+
576581
let w = winwidth(0)
577582
call setline(2, repeat('a', w + 2))
578583
let win_nosbr = win_getid()

src/testdir/test_functions.vim

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,6 +3366,46 @@ func Test_getmousepos()
33663366
\ line: 1,
33673367
\ column: 1,
33683368
\ }, getmousepos())
3369+
call test_setmouse(1, 2)
3370+
call assert_equal(#{
3371+
\ screenrow: 1,
3372+
\ screencol: 2,
3373+
\ winid: win_getid(),
3374+
\ winrow: 1,
3375+
\ wincol: 2,
3376+
\ line: 1,
3377+
\ column: 1,
3378+
\ }, getmousepos())
3379+
call test_setmouse(1, 8)
3380+
call assert_equal(#{
3381+
\ screenrow: 1,
3382+
\ screencol: 8,
3383+
\ winid: win_getid(),
3384+
\ winrow: 1,
3385+
\ wincol: 8,
3386+
\ line: 1,
3387+
\ column: 1,
3388+
\ }, getmousepos())
3389+
call test_setmouse(1, 9)
3390+
call assert_equal(#{
3391+
\ screenrow: 1,
3392+
\ screencol: 9,
3393+
\ winid: win_getid(),
3394+
\ winrow: 1,
3395+
\ wincol: 9,
3396+
\ line: 1,
3397+
\ column: 2,
3398+
\ }, getmousepos())
3399+
call test_setmouse(1, 12)
3400+
call assert_equal(#{
3401+
\ screenrow: 1,
3402+
\ screencol: 12,
3403+
\ winid: win_getid(),
3404+
\ winrow: 1,
3405+
\ wincol: 12,
3406+
\ line: 1,
3407+
\ column: 2,
3408+
\ }, getmousepos())
33693409
call test_setmouse(1, 25)
33703410
call assert_equal(#{
33713411
\ screenrow: 1,

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
2022,
707709
/**/
708710
2021,
709711
/**/

0 commit comments

Comments
 (0)