Skip to content

Commit db3a205

Browse files
committed
patch 8.1.2304: cannot get the mouse position when getting a mouse click
Problem: Cannot get the mouse position when getting a mouse click. Solution: Add getmousepos().
1 parent 08f2363 commit db3a205

9 files changed

Lines changed: 204 additions & 57 deletions

File tree

runtime/doc/eval.txt

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,15 +1956,11 @@ v:mouse_winid Window ID for a mouse click obtained with |getchar()|.
19561956

19571957
*v:mouse_lnum* *mouse_lnum-variable*
19581958
v:mouse_lnum Line number for a mouse click obtained with |getchar()|.
1959-
Also used for a click in a popup window when the filter is
1960-
invoked.
19611959
This is the text line number, not the screen line number. The
19621960
value is zero when there was no mouse button click.
19631961

19641962
*v:mouse_col* *mouse_col-variable*
19651963
v:mouse_col Column number for a mouse click obtained with |getchar()|.
1966-
Also used for a click in a popup window when the filter is
1967-
invoked.
19681964
This is the screen column number, like with |virtcol()|. The
19691965
value is zero when there was no mouse button click.
19701966

@@ -2484,6 +2480,7 @@ getline({lnum}) String line {lnum} of current buffer
24842480
getline({lnum}, {end}) List lines {lnum} to {end} of current buffer
24852481
getloclist({nr} [, {what}]) List list of location list items
24862482
getmatches([{win}]) List list of current matches
2483+
getmousepos() Dict last known mouse position
24872484
getpid() Number process ID of Vim
24882485
getpos({expr}) List position of cursor, mark, etc.
24892486
getqflist([{what}]) List list of quickfix items
@@ -4922,8 +4919,9 @@ getchar([expr]) *getchar()*
49224919

49234920
When the user clicks a mouse button, the mouse event will be
49244921
returned. The position can then be found in |v:mouse_col|,
4925-
|v:mouse_lnum|, |v:mouse_winid| and |v:mouse_win|. This
4926-
example positions the mouse as it would normally happen: >
4922+
|v:mouse_lnum|, |v:mouse_winid| and |v:mouse_win|.
4923+
|getmousepos()| can also be used. This example positions the
4924+
mouse as it would normally happen: >
49274925
let c = getchar()
49284926
if c == "\<LeftMouse>" && v:mouse_win > 0
49294927
exe v:mouse_win . "wincmd w"
@@ -5333,6 +5331,35 @@ getmatches([{win}]) *getmatches()*
53335331
'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
53345332
:unlet m
53355333
<
5334+
getmousepos() *getmousepos()*
5335+
Returns a Dictionary with the last known position of the
5336+
mouse. This can be used in a mapping for a mouse click or in
5337+
a filter of a popup window. The items are:
5338+
screenrow screen row
5339+
screencol screen column
5340+
winid Window ID of the click
5341+
winrow row inside "winid"
5342+
wincol column inside "winid"
5343+
line text line inside "winid"
5344+
column text column inside "winid"
5345+
All numbers are 1-based.
5346+
5347+
If not over a window, e.g. when in the command line, then only
5348+
"screenrow" and "screencol" are valid, the others are zero.
5349+
5350+
When on the status line below a window or the vertical
5351+
separater right of a window, the "line" and "column" values
5352+
are zero.
5353+
5354+
When the position is after the text then "column" is the
5355+
length of the text in bytes.
5356+
5357+
If the mouse is over a popup window then that window is used.
5358+
5359+
5360+
When using |getchar()| the Vim variables |v:mouse_lnum|,
5361+
|v:mouse_col| and |v:mouse_winid| also provide these values.
5362+
53365363
*getpid()*
53375364
getpid() Return a Number which is the process ID of the Vim process.
53385365
On Unix and MS-Windows this is a unique number, until Vim

runtime/doc/popup.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -862,10 +862,8 @@ Some recommended key actions:
862862
cursor keys select another entry
863863
Tab accept current suggestion
864864

865-
A mouse click arrives as <LeftMouse>. The coordinates are in |v:mouse_col|
866-
and |v:mouse_lnum|. |v:mouse_winid| holds the window ID, |v:mouse_win| is
867-
always zero. The top-left screen cell of the popup is col 1, row 1 (not
868-
counting the border).
865+
A mouse click arrives as <LeftMouse>. The coordinates can be obtained with
866+
|mousegetpos()|.
869867

870868
Vim provides standard filters |popup_filter_menu()| and
871869
|popup_filter_yesno()|.

src/evalfunc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ static funcentry_T global_functions[] =
465465
{"getline", 1, 2, FEARG_1, f_getline},
466466
{"getloclist", 1, 2, 0, f_getloclist},
467467
{"getmatches", 0, 1, 0, f_getmatches},
468+
{"getmousepos", 0, 0, 0, f_getmousepos},
468469
{"getpid", 0, 0, 0, f_getpid},
469470
{"getpos", 1, 1, FEARG_1, f_getpos},
470471
{"getqflist", 0, 1, 0, f_getqflist},

src/mouse.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2822,6 +2822,7 @@ mouse_comp_pos(
28222822
int retval = FALSE;
28232823
int off;
28242824
int count;
2825+
char_u *p;
28252826

28262827
#ifdef FEAT_RIGHTLEFT
28272828
if (win->w_p_rl)
@@ -2881,6 +2882,11 @@ mouse_comp_pos(
28812882
col += row * (win->w_width - off);
28822883
// add skip column (for long wrapping line)
28832884
col += win->w_skipcol;
2885+
// limit to text length plus one
2886+
p = ml_get_buf(win->w_buffer, lnum, FALSE);
2887+
count = STRLEN(p);
2888+
if (col > count)
2889+
col = count;
28842890
}
28852891

28862892
if (!win->w_p_wrap)
@@ -3001,3 +3007,61 @@ vcol2col(win_T *wp, linenr_T lnum, int vcol)
30013007
return (int)(ptr - line);
30023008
}
30033009
#endif
3010+
3011+
#if defined(FEAT_EVAL) || defined(PROTO)
3012+
void
3013+
f_getmousepos(typval_T *argvars UNUSED, typval_T *rettv)
3014+
{
3015+
dict_T *d;
3016+
win_T *wp;
3017+
int row = mouse_row;
3018+
int col = mouse_col;
3019+
varnumber_T winid = 0;
3020+
varnumber_T winrow = 0;
3021+
varnumber_T wincol = 0;
3022+
varnumber_T line = 0;
3023+
varnumber_T column = 0;
3024+
3025+
if (rettv_dict_alloc(rettv) != OK)
3026+
return;
3027+
d = rettv->vval.v_dict;
3028+
3029+
dict_add_number(d, "screenrow", (varnumber_T)mouse_row + 1);
3030+
dict_add_number(d, "screencol", (varnumber_T)mouse_col + 1);
3031+
3032+
wp = mouse_find_win(&row, &col, FIND_POPUP);
3033+
if (wp != NULL)
3034+
{
3035+
int top_off = 0;
3036+
int left_off = 0;
3037+
int height = wp->w_height + wp->w_status_height;
3038+
3039+
#ifdef FEAT_TEXT_PROP
3040+
if (WIN_IS_POPUP(wp))
3041+
{
3042+
top_off = popup_top_extra(wp);
3043+
left_off = popup_left_extra(wp);
3044+
height = popup_height(wp);
3045+
}
3046+
#endif
3047+
if (row < height)
3048+
{
3049+
winid = wp->w_id;
3050+
winrow = row + 1;
3051+
wincol = col + 1;
3052+
row -= top_off;
3053+
col -= left_off;
3054+
if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width)
3055+
{
3056+
mouse_comp_pos(wp, &row, &col, &line, NULL);
3057+
column = col + 1;
3058+
}
3059+
}
3060+
}
3061+
dict_add_number(d, "winid", winid);
3062+
dict_add_number(d, "winrow", winrow);
3063+
dict_add_number(d, "wincol", wincol);
3064+
dict_add_number(d, "line", line);
3065+
dict_add_number(d, "column", column);
3066+
}
3067+
#endif

src/popupwin.c

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,15 @@ popup_top_extra(win_T *wp)
10461046
return extra;
10471047
}
10481048

1049+
/*
1050+
* Get the padding plus border at the left.
1051+
*/
1052+
int
1053+
popup_left_extra(win_T *wp)
1054+
{
1055+
return wp->w_popup_border[3] + wp->w_popup_padding[3];
1056+
}
1057+
10491058
/*
10501059
* Return the height of popup window "wp", including border and padding.
10511060
*/
@@ -2908,33 +2917,12 @@ invoke_popup_filter(win_T *wp, int c)
29082917

29092918
argv[2].v_type = VAR_UNKNOWN;
29102919

2911-
if (is_mouse_key(c))
2912-
{
2913-
int row = mouse_row - wp->w_winrow;
2914-
int col = mouse_col - wp->w_wincol;
2915-
linenr_T lnum;
2916-
2917-
if (row >= 0 && col >= 0)
2918-
{
2919-
(void)mouse_comp_pos(wp, &row, &col, &lnum, NULL);
2920-
set_vim_var_nr(VV_MOUSE_LNUM, lnum);
2921-
set_vim_var_nr(VV_MOUSE_COL, col + 1);
2922-
set_vim_var_nr(VV_MOUSE_WINID, wp->w_id);
2923-
}
2924-
}
2925-
29262920
// NOTE: The callback might close the popup and make "wp" invalid.
29272921
call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv);
29282922
if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum)
29292923
popup_highlight_curline(wp);
29302924
res = tv_get_number(&rettv);
29312925

2932-
if (is_mouse_key(c))
2933-
{
2934-
set_vim_var_nr(VV_MOUSE_LNUM, 0);
2935-
set_vim_var_nr(VV_MOUSE_COL, 0);
2936-
set_vim_var_nr(VV_MOUSE_WINID, wp->w_id);
2937-
}
29382926
vim_free(argv[1].vval.v_string);
29392927
clear_tv(&rettv);
29402928
return res;

src/proto/mouse.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ int check_termcode_mouse(char_u *tp, int *slen, char_u *key_name, char_u *modifi
1717
int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump, int *plines_cache);
1818
win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup);
1919
int vcol2col(win_T *wp, linenr_T lnum, int vcol);
20+
void f_getmousepos(typval_T *argvars, typval_T *rettv);
2021
/* vim: set ft=c : */

src/testdir/test_functions.vim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,7 @@ func Test_getchar()
13311331
call feedkeys('a', '')
13321332
call assert_equal(char2nr('a'), getchar())
13331333

1334+
call setline(1, 'xxxx')
13341335
call test_setmouse(1, 3)
13351336
let v:mouse_win = 9
13361337
let v:mouse_winid = 9
@@ -1342,6 +1343,7 @@ func Test_getchar()
13421343
call assert_equal(win_getid(1), v:mouse_winid)
13431344
call assert_equal(1, v:mouse_lnum)
13441345
call assert_equal(3, v:mouse_col)
1346+
enew!
13451347
endfunc
13461348

13471349
func Test_libcall_libcallnr()

src/testdir/test_popupwin.vim

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2205,42 +2205,106 @@ endfunc
22052205

22062206
func Test_popupwin_filter_mouse()
22072207
func MyPopupFilter(winid, c)
2208-
let g:got_mouse_col = v:mouse_col
2209-
let g:got_mouse_lnum = v:mouse_lnum
2210-
let g:got_mouse_winid = v:mouse_winid
2208+
let g:got_mousepos = getmousepos()
22112209
return 0
22122210
endfunc
22132211

2214-
let winid = popup_create(['short', 'long line that will wrap', 'short'], #{
2215-
\ line: 4,
2216-
\ col: 8,
2212+
call setline(1, ['.'->repeat(25)]->repeat(10))
2213+
let winid = popup_create(['short', 'long line that will wrap', 'other'], #{
2214+
\ line: 2,
2215+
\ col: 4,
22172216
\ maxwidth: 12,
2217+
\ padding: [],
2218+
\ border: [],
22182219
\ filter: 'MyPopupFilter',
22192220
\ })
22202221
redraw
2221-
call test_setmouse(4, 8)
2222-
call feedkeys("\<LeftMouse>", 'xt')
2223-
call assert_equal(1, g:got_mouse_col)
2224-
call assert_equal(1, g:got_mouse_lnum)
2225-
call assert_equal(winid, g:got_mouse_winid)
2226-
2227-
call test_setmouse(5, 8)
2228-
call feedkeys("\<LeftMouse>", 'xt')
2229-
call assert_equal(1, g:got_mouse_col)
2230-
call assert_equal(2, g:got_mouse_lnum)
2231-
2232-
call test_setmouse(6, 8)
2233-
call feedkeys("\<LeftMouse>", 'xt')
2234-
call assert_equal(13, g:got_mouse_col)
2235-
call assert_equal(2, g:got_mouse_lnum)
2222+
" 123456789012345678901
2223+
" 1 .....................
2224+
" 2 ...+--------------+..
2225+
" 3 ...| |..
2226+
" 4 ...| short |..
2227+
" 5 ...| long line th |..
2228+
" 6 ...| at will wrap |..
2229+
" 7 ...| other |..
2230+
" 8 ...| |..
2231+
" 9 ...+--------------+..
2232+
" 10 .....................
2233+
let tests = []
2234+
2235+
func AddItemOutsidePopup(tests, row, col)
2236+
eval a:tests->add(#{clickrow: a:row, clickcol: a:col, result: #{
2237+
\ screenrow: a:row, screencol: a:col,
2238+
\ winid: win_getid(), winrow: a:row, wincol: a:col,
2239+
\ line: a:row, column: a:col,
2240+
\ }})
2241+
endfunc
2242+
func AddItemInPopupBorder(tests, winid, row, col)
2243+
eval a:tests->add(#{clickrow: a:row, clickcol: a:col, result: #{
2244+
\ screenrow: a:row, screencol: a:col,
2245+
\ winid: a:winid, winrow: a:row - 1, wincol: a:col - 3,
2246+
\ line: 0, column: 0,
2247+
\ }})
2248+
endfunc
2249+
func AddItemInPopupText(tests, winid, row, col, textline, textcol)
2250+
eval a:tests->add(#{clickrow: a:row, clickcol: a:col, result: #{
2251+
\ screenrow: a:row, screencol: a:col,
2252+
\ winid: a:winid, winrow: a:row - 1, wincol: a:col - 3,
2253+
\ line: a:textline, column: a:textcol,
2254+
\ }})
2255+
endfunc
22362256

2237-
call test_setmouse(7, 20)
2238-
call feedkeys("\<LeftMouse>", 'xt')
2239-
call assert_equal(13, g:got_mouse_col)
2240-
call assert_equal(3, g:got_mouse_lnum)
2241-
call assert_equal(winid, g:got_mouse_winid)
2257+
" above and below popup
2258+
for c in range(1, 21)
2259+
call AddItemOutsidePopup(tests, 1, c)
2260+
call AddItemOutsidePopup(tests, 10, c)
2261+
endfor
2262+
" left and right of popup
2263+
for r in range(1, 10)
2264+
call AddItemOutsidePopup(tests, r, 3)
2265+
call AddItemOutsidePopup(tests, r, 20)
2266+
endfor
2267+
" top and bottom in popup
2268+
for c in range(4, 19)
2269+
call AddItemInPopupBorder(tests, winid, 2, c)
2270+
call AddItemInPopupBorder(tests, winid, 3, c)
2271+
call AddItemInPopupBorder(tests, winid, 8, c)
2272+
call AddItemInPopupBorder(tests, winid, 9, c)
2273+
endfor
2274+
" left and right margin in popup
2275+
for r in range(2, 9)
2276+
call AddItemInPopupBorder(tests, winid, r, 4)
2277+
call AddItemInPopupBorder(tests, winid, r, 5)
2278+
call AddItemInPopupBorder(tests, winid, r, 18)
2279+
call AddItemInPopupBorder(tests, winid, r, 19)
2280+
endfor
2281+
" text "short"
2282+
call AddItemInPopupText(tests, winid, 4, 6, 1, 1)
2283+
call AddItemInPopupText(tests, winid, 4, 10, 1, 5)
2284+
call AddItemInPopupText(tests, winid, 4, 11, 1, 6)
2285+
call AddItemInPopupText(tests, winid, 4, 17, 1, 6)
2286+
" text "long line th"
2287+
call AddItemInPopupText(tests, winid, 5, 6, 2, 1)
2288+
call AddItemInPopupText(tests, winid, 5, 10, 2, 5)
2289+
call AddItemInPopupText(tests, winid, 5, 17, 2, 12)
2290+
" text "at will wrap"
2291+
call AddItemInPopupText(tests, winid, 6, 6, 2, 13)
2292+
call AddItemInPopupText(tests, winid, 6, 10, 2, 17)
2293+
call AddItemInPopupText(tests, winid, 6, 17, 2, 24)
2294+
" text "other"
2295+
call AddItemInPopupText(tests, winid, 7, 6, 3, 1)
2296+
call AddItemInPopupText(tests, winid, 7, 10, 3, 5)
2297+
call AddItemInPopupText(tests, winid, 7, 11, 3, 6)
2298+
call AddItemInPopupText(tests, winid, 7, 17, 3, 6)
2299+
2300+
for item in tests
2301+
call test_setmouse(item.clickrow, item.clickcol)
2302+
call feedkeys("\<LeftMouse>", 'xt')
2303+
call assert_equal(item.result, g:got_mousepos)
2304+
endfor
22422305

22432306
call popup_close(winid)
2307+
enew!
22442308
delfunc MyPopupFilter
22452309
endfunc
22462310

src/version.c

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

742742
static int included_patches[] =
743743
{ /* Add new patch number below this line */
744+
/**/
745+
2304,
744746
/**/
745747
2303,
746748
/**/

0 commit comments

Comments
 (0)