mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:9.0.2022: getmousepos() returns wrong index for TAB char (#25636)
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: vim/vim#13321
b583eda703
This commit is contained in:
parent
99b1163b5a
commit
bcda800933
2
runtime/doc/builtin.txt
generated
2
runtime/doc/builtin.txt
generated
@ -8509,6 +8509,8 @@ virtcol2col({winid}, {lnum}, {col}) *virtcol2col()*
|
|||||||
character in window {winid} at buffer line {lnum} and virtual
|
character in window {winid} at buffer line {lnum} and virtual
|
||||||
column {col}.
|
column {col}.
|
||||||
|
|
||||||
|
If buffer line {lnum} is an empty line, 0 is returned.
|
||||||
|
|
||||||
If {col} is greater than the last virtual column in line
|
If {col} is greater than the last virtual column in line
|
||||||
{lnum}, then the byte index of the character at the last
|
{lnum}, then the byte index of the character at the last
|
||||||
virtual column is returned.
|
virtual column is returned.
|
||||||
|
2
runtime/lua/vim/_meta/vimfn.lua
generated
2
runtime/lua/vim/_meta/vimfn.lua
generated
@ -10099,6 +10099,8 @@ function vim.fn.virtcol(expr, list, winid) end
|
|||||||
--- character in window {winid} at buffer line {lnum} and virtual
|
--- character in window {winid} at buffer line {lnum} and virtual
|
||||||
--- column {col}.
|
--- column {col}.
|
||||||
---
|
---
|
||||||
|
--- If buffer line {lnum} is an empty line, 0 is returned.
|
||||||
|
---
|
||||||
--- If {col} is greater than the last virtual column in line
|
--- If {col} is greater than the last virtual column in line
|
||||||
--- {lnum}, then the byte index of the character at the last
|
--- {lnum}, then the byte index of the character at the last
|
||||||
--- virtual column is returned.
|
--- virtual column is returned.
|
||||||
|
@ -12107,6 +12107,8 @@ M.funcs = {
|
|||||||
character in window {winid} at buffer line {lnum} and virtual
|
character in window {winid} at buffer line {lnum} and virtual
|
||||||
column {col}.
|
column {col}.
|
||||||
|
|
||||||
|
If buffer line {lnum} is an empty line, 0 is returned.
|
||||||
|
|
||||||
If {col} is greater than the last virtual column in line
|
If {col} is greater than the last virtual column in line
|
||||||
{lnum}, then the byte index of the character at the last
|
{lnum}, then the byte index of the character at the last
|
||||||
virtual column is returned.
|
virtual column is returned.
|
||||||
|
@ -1754,7 +1754,7 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a virtual (screen) column to a character column.
|
/// Convert a virtual (screen) column to a character column.
|
||||||
/// The first column is one.
|
/// The first column is zero.
|
||||||
colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol)
|
colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol)
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
@ -1763,7 +1763,11 @@ colnr_T vcol2col(win_T *const wp, const linenr_T lnum, const colnr_T vcol)
|
|||||||
chartabsize_T cts;
|
chartabsize_T cts;
|
||||||
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
|
init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
|
||||||
while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL) {
|
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);
|
MB_PTR_ADV(cts.cts_ptr);
|
||||||
}
|
}
|
||||||
clear_chartabsize_arg(&cts);
|
clear_chartabsize_arg(&cts);
|
||||||
|
@ -1142,13 +1142,17 @@ void f_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
/// returned.
|
/// returned.
|
||||||
static int virtcol2col(win_T *wp, linenr_T lnum, int vcol)
|
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 *line = ml_get_buf(wp->w_buffer, lnum);
|
char *line = ml_get_buf(wp->w_buffer, lnum);
|
||||||
char *p = line + offset;
|
char *p = line + offset;
|
||||||
|
|
||||||
// For a multibyte character, need to return the column number of the first byte.
|
if (*p == NUL) {
|
||||||
MB_PTR_BACK(line, p);
|
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);
|
return (int)(p - line + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,6 +573,11 @@ func Test_virtcol2col()
|
|||||||
call assert_equal(8, virtcol2col(0, 1, 7))
|
call assert_equal(8, virtcol2col(0, 1, 7))
|
||||||
call assert_equal(8, virtcol2col(0, 1, 8))
|
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)
|
let w = winwidth(0)
|
||||||
call setline(2, repeat('a', w + 2))
|
call setline(2, repeat('a', w + 2))
|
||||||
let win_nosbr = win_getid()
|
let win_nosbr = win_getid()
|
||||||
|
@ -3069,6 +3069,46 @@ func Test_getmousepos()
|
|||||||
\ line: 1,
|
\ line: 1,
|
||||||
\ column: 1,
|
\ column: 1,
|
||||||
\ }, getmousepos())
|
\ }, getmousepos())
|
||||||
|
call Ntest_setmouse(1, 2)
|
||||||
|
call assert_equal(#{
|
||||||
|
\ screenrow: 1,
|
||||||
|
\ screencol: 2,
|
||||||
|
\ winid: win_getid(),
|
||||||
|
\ winrow: 1,
|
||||||
|
\ wincol: 2,
|
||||||
|
\ line: 1,
|
||||||
|
\ column: 1,
|
||||||
|
\ }, getmousepos())
|
||||||
|
call Ntest_setmouse(1, 8)
|
||||||
|
call assert_equal(#{
|
||||||
|
\ screenrow: 1,
|
||||||
|
\ screencol: 8,
|
||||||
|
\ winid: win_getid(),
|
||||||
|
\ winrow: 1,
|
||||||
|
\ wincol: 8,
|
||||||
|
\ line: 1,
|
||||||
|
\ column: 1,
|
||||||
|
\ }, getmousepos())
|
||||||
|
call Ntest_setmouse(1, 9)
|
||||||
|
call assert_equal(#{
|
||||||
|
\ screenrow: 1,
|
||||||
|
\ screencol: 9,
|
||||||
|
\ winid: win_getid(),
|
||||||
|
\ winrow: 1,
|
||||||
|
\ wincol: 9,
|
||||||
|
\ line: 1,
|
||||||
|
\ column: 2,
|
||||||
|
\ }, getmousepos())
|
||||||
|
call Ntest_setmouse(1, 12)
|
||||||
|
call assert_equal(#{
|
||||||
|
\ screenrow: 1,
|
||||||
|
\ screencol: 12,
|
||||||
|
\ winid: win_getid(),
|
||||||
|
\ winrow: 1,
|
||||||
|
\ wincol: 12,
|
||||||
|
\ line: 1,
|
||||||
|
\ column: 2,
|
||||||
|
\ }, getmousepos())
|
||||||
call Ntest_setmouse(1, 25)
|
call Ntest_setmouse(1, 25)
|
||||||
call assert_equal(#{
|
call assert_equal(#{
|
||||||
\ screenrow: 1,
|
\ screenrow: 1,
|
||||||
|
Loading…
Reference in New Issue
Block a user