0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

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().
This commit is contained in:
Bram Moolenaar
2019-11-16 18:22:41 +01:00
parent 08f23636ae
commit db3a205147
9 changed files with 202 additions and 55 deletions

View File

@@ -1956,15 +1956,11 @@ v:mouse_winid Window ID for a mouse click obtained with |getchar()|.
*v:mouse_lnum* *mouse_lnum-variable*
v:mouse_lnum Line number for a mouse click obtained with |getchar()|.
Also used for a click in a popup window when the filter is
invoked.
This is the text line number, not the screen line number. The
value is zero when there was no mouse button click.
*v:mouse_col* *mouse_col-variable*
v:mouse_col Column number for a mouse click obtained with |getchar()|.
Also used for a click in a popup window when the filter is
invoked.
This is the screen column number, like with |virtcol()|. The
value is zero when there was no mouse button click.
@@ -2484,6 +2480,7 @@ getline({lnum}) String line {lnum} of current buffer
getline({lnum}, {end}) List lines {lnum} to {end} of current buffer
getloclist({nr} [, {what}]) List list of location list items
getmatches([{win}]) List list of current matches
getmousepos() Dict last known mouse position
getpid() Number process ID of Vim
getpos({expr}) List position of cursor, mark, etc.
getqflist([{what}]) List list of quickfix items
@@ -4922,8 +4919,9 @@ getchar([expr]) *getchar()*
When the user clicks a mouse button, the mouse event will be
returned. The position can then be found in |v:mouse_col|,
|v:mouse_lnum|, |v:mouse_winid| and |v:mouse_win|. This
example positions the mouse as it would normally happen: >
|v:mouse_lnum|, |v:mouse_winid| and |v:mouse_win|.
|getmousepos()| can also be used. This example positions the
mouse as it would normally happen: >
let c = getchar()
if c == "\<LeftMouse>" && v:mouse_win > 0
exe v:mouse_win . "wincmd w"
@@ -5333,6 +5331,35 @@ getmatches([{win}]) *getmatches()*
'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
:unlet m
<
getmousepos() *getmousepos()*
Returns a Dictionary with the last known position of the
mouse. This can be used in a mapping for a mouse click or in
a filter of a popup window. The items are:
screenrow screen row
screencol screen column
winid Window ID of the click
winrow row inside "winid"
wincol column inside "winid"
line text line inside "winid"
column text column inside "winid"
All numbers are 1-based.
If not over a window, e.g. when in the command line, then only
"screenrow" and "screencol" are valid, the others are zero.
When on the status line below a window or the vertical
separater right of a window, the "line" and "column" values
are zero.
When the position is after the text then "column" is the
length of the text in bytes.
If the mouse is over a popup window then that window is used.
When using |getchar()| the Vim variables |v:mouse_lnum|,
|v:mouse_col| and |v:mouse_winid| also provide these values.
*getpid()*
getpid() Return a Number which is the process ID of the Vim process.
On Unix and MS-Windows this is a unique number, until Vim

View File

@@ -862,10 +862,8 @@ Some recommended key actions:
cursor keys select another entry
Tab accept current suggestion
A mouse click arrives as <LeftMouse>. The coordinates are in |v:mouse_col|
and |v:mouse_lnum|. |v:mouse_winid| holds the window ID, |v:mouse_win| is
always zero. The top-left screen cell of the popup is col 1, row 1 (not
counting the border).
A mouse click arrives as <LeftMouse>. The coordinates can be obtained with
|mousegetpos()|.
Vim provides standard filters |popup_filter_menu()| and
|popup_filter_yesno()|.

View File

@@ -465,6 +465,7 @@ static funcentry_T global_functions[] =
{"getline", 1, 2, FEARG_1, f_getline},
{"getloclist", 1, 2, 0, f_getloclist},
{"getmatches", 0, 1, 0, f_getmatches},
{"getmousepos", 0, 0, 0, f_getmousepos},
{"getpid", 0, 0, 0, f_getpid},
{"getpos", 1, 1, FEARG_1, f_getpos},
{"getqflist", 0, 1, 0, f_getqflist},

View File

@@ -2822,6 +2822,7 @@ mouse_comp_pos(
int retval = FALSE;
int off;
int count;
char_u *p;
#ifdef FEAT_RIGHTLEFT
if (win->w_p_rl)
@@ -2881,6 +2882,11 @@ mouse_comp_pos(
col += row * (win->w_width - off);
// add skip column (for long wrapping line)
col += win->w_skipcol;
// limit to text length plus one
p = ml_get_buf(win->w_buffer, lnum, FALSE);
count = STRLEN(p);
if (col > count)
col = count;
}
if (!win->w_p_wrap)
@@ -3001,3 +3007,61 @@ vcol2col(win_T *wp, linenr_T lnum, int vcol)
return (int)(ptr - line);
}
#endif
#if defined(FEAT_EVAL) || defined(PROTO)
void
f_getmousepos(typval_T *argvars UNUSED, typval_T *rettv)
{
dict_T *d;
win_T *wp;
int row = mouse_row;
int col = mouse_col;
varnumber_T winid = 0;
varnumber_T winrow = 0;
varnumber_T wincol = 0;
varnumber_T line = 0;
varnumber_T column = 0;
if (rettv_dict_alloc(rettv) != OK)
return;
d = rettv->vval.v_dict;
dict_add_number(d, "screenrow", (varnumber_T)mouse_row + 1);
dict_add_number(d, "screencol", (varnumber_T)mouse_col + 1);
wp = mouse_find_win(&row, &col, FIND_POPUP);
if (wp != NULL)
{
int top_off = 0;
int left_off = 0;
int height = wp->w_height + wp->w_status_height;
#ifdef FEAT_TEXT_PROP
if (WIN_IS_POPUP(wp))
{
top_off = popup_top_extra(wp);
left_off = popup_left_extra(wp);
height = popup_height(wp);
}
#endif
if (row < height)
{
winid = wp->w_id;
winrow = row + 1;
wincol = col + 1;
row -= top_off;
col -= left_off;
if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width)
{
mouse_comp_pos(wp, &row, &col, &line, NULL);
column = col + 1;
}
}
}
dict_add_number(d, "winid", winid);
dict_add_number(d, "winrow", winrow);
dict_add_number(d, "wincol", wincol);
dict_add_number(d, "line", line);
dict_add_number(d, "column", column);
}
#endif

View File

@@ -1046,6 +1046,15 @@ popup_top_extra(win_T *wp)
return extra;
}
/*
* Get the padding plus border at the left.
*/
int
popup_left_extra(win_T *wp)
{
return wp->w_popup_border[3] + wp->w_popup_padding[3];
}
/*
* Return the height of popup window "wp", including border and padding.
*/
@@ -2908,33 +2917,12 @@ invoke_popup_filter(win_T *wp, int c)
argv[2].v_type = VAR_UNKNOWN;
if (is_mouse_key(c))
{
int row = mouse_row - wp->w_winrow;
int col = mouse_col - wp->w_wincol;
linenr_T lnum;
if (row >= 0 && col >= 0)
{
(void)mouse_comp_pos(wp, &row, &col, &lnum, NULL);
set_vim_var_nr(VV_MOUSE_LNUM, lnum);
set_vim_var_nr(VV_MOUSE_COL, col + 1);
set_vim_var_nr(VV_MOUSE_WINID, wp->w_id);
}
}
// NOTE: The callback might close the popup and make "wp" invalid.
call_callback(&wp->w_filter_cb, -1, &rettv, 2, argv);
if (win_valid_popup(wp) && old_lnum != wp->w_cursor.lnum)
popup_highlight_curline(wp);
res = tv_get_number(&rettv);
if (is_mouse_key(c))
{
set_vim_var_nr(VV_MOUSE_LNUM, 0);
set_vim_var_nr(VV_MOUSE_COL, 0);
set_vim_var_nr(VV_MOUSE_WINID, wp->w_id);
}
vim_free(argv[1].vval.v_string);
clear_tv(&rettv);
return res;

View File

@@ -17,4 +17,5 @@ int check_termcode_mouse(char_u *tp, int *slen, char_u *key_name, char_u *modifi
int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump, int *plines_cache);
win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup);
int vcol2col(win_T *wp, linenr_T lnum, int vcol);
void f_getmousepos(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */

View File

@@ -1331,6 +1331,7 @@ func Test_getchar()
call feedkeys('a', '')
call assert_equal(char2nr('a'), getchar())
call setline(1, 'xxxx')
call test_setmouse(1, 3)
let v:mouse_win = 9
let v:mouse_winid = 9
@@ -1342,6 +1343,7 @@ func Test_getchar()
call assert_equal(win_getid(1), v:mouse_winid)
call assert_equal(1, v:mouse_lnum)
call assert_equal(3, v:mouse_col)
enew!
endfunc
func Test_libcall_libcallnr()

View File

@@ -2205,42 +2205,106 @@ endfunc
func Test_popupwin_filter_mouse()
func MyPopupFilter(winid, c)
let g:got_mouse_col = v:mouse_col
let g:got_mouse_lnum = v:mouse_lnum
let g:got_mouse_winid = v:mouse_winid
let g:got_mousepos = getmousepos()
return 0
endfunc
let winid = popup_create(['short', 'long line that will wrap', 'short'], #{
\ line: 4,
\ col: 8,
call setline(1, ['.'->repeat(25)]->repeat(10))
let winid = popup_create(['short', 'long line that will wrap', 'other'], #{
\ line: 2,
\ col: 4,
\ maxwidth: 12,
\ padding: [],
\ border: [],
\ filter: 'MyPopupFilter',
\ })
redraw
call test_setmouse(4, 8)
call feedkeys("\<LeftMouse>", 'xt')
call assert_equal(1, g:got_mouse_col)
call assert_equal(1, g:got_mouse_lnum)
call assert_equal(winid, g:got_mouse_winid)
" 123456789012345678901
" 1 .....................
" 2 ...+--------------+..
" 3 ...| |..
" 4 ...| short |..
" 5 ...| long line th |..
" 6 ...| at will wrap |..
" 7 ...| other |..
" 8 ...| |..
" 9 ...+--------------+..
" 10 .....................
let tests = []
call test_setmouse(5, 8)
call feedkeys("\<LeftMouse>", 'xt')
call assert_equal(1, g:got_mouse_col)
call assert_equal(2, g:got_mouse_lnum)
func AddItemOutsidePopup(tests, row, col)
eval a:tests->add(#{clickrow: a:row, clickcol: a:col, result: #{
\ screenrow: a:row, screencol: a:col,
\ winid: win_getid(), winrow: a:row, wincol: a:col,
\ line: a:row, column: a:col,
\ }})
endfunc
func AddItemInPopupBorder(tests, winid, row, col)
eval a:tests->add(#{clickrow: a:row, clickcol: a:col, result: #{
\ screenrow: a:row, screencol: a:col,
\ winid: a:winid, winrow: a:row - 1, wincol: a:col - 3,
\ line: 0, column: 0,
\ }})
endfunc
func AddItemInPopupText(tests, winid, row, col, textline, textcol)
eval a:tests->add(#{clickrow: a:row, clickcol: a:col, result: #{
\ screenrow: a:row, screencol: a:col,
\ winid: a:winid, winrow: a:row - 1, wincol: a:col - 3,
\ line: a:textline, column: a:textcol,
\ }})
endfunc
call test_setmouse(6, 8)
call feedkeys("\<LeftMouse>", 'xt')
call assert_equal(13, g:got_mouse_col)
call assert_equal(2, g:got_mouse_lnum)
" above and below popup
for c in range(1, 21)
call AddItemOutsidePopup(tests, 1, c)
call AddItemOutsidePopup(tests, 10, c)
endfor
" left and right of popup
for r in range(1, 10)
call AddItemOutsidePopup(tests, r, 3)
call AddItemOutsidePopup(tests, r, 20)
endfor
" top and bottom in popup
for c in range(4, 19)
call AddItemInPopupBorder(tests, winid, 2, c)
call AddItemInPopupBorder(tests, winid, 3, c)
call AddItemInPopupBorder(tests, winid, 8, c)
call AddItemInPopupBorder(tests, winid, 9, c)
endfor
" left and right margin in popup
for r in range(2, 9)
call AddItemInPopupBorder(tests, winid, r, 4)
call AddItemInPopupBorder(tests, winid, r, 5)
call AddItemInPopupBorder(tests, winid, r, 18)
call AddItemInPopupBorder(tests, winid, r, 19)
endfor
" text "short"
call AddItemInPopupText(tests, winid, 4, 6, 1, 1)
call AddItemInPopupText(tests, winid, 4, 10, 1, 5)
call AddItemInPopupText(tests, winid, 4, 11, 1, 6)
call AddItemInPopupText(tests, winid, 4, 17, 1, 6)
" text "long line th"
call AddItemInPopupText(tests, winid, 5, 6, 2, 1)
call AddItemInPopupText(tests, winid, 5, 10, 2, 5)
call AddItemInPopupText(tests, winid, 5, 17, 2, 12)
" text "at will wrap"
call AddItemInPopupText(tests, winid, 6, 6, 2, 13)
call AddItemInPopupText(tests, winid, 6, 10, 2, 17)
call AddItemInPopupText(tests, winid, 6, 17, 2, 24)
" text "other"
call AddItemInPopupText(tests, winid, 7, 6, 3, 1)
call AddItemInPopupText(tests, winid, 7, 10, 3, 5)
call AddItemInPopupText(tests, winid, 7, 11, 3, 6)
call AddItemInPopupText(tests, winid, 7, 17, 3, 6)
call test_setmouse(7, 20)
for item in tests
call test_setmouse(item.clickrow, item.clickcol)
call feedkeys("\<LeftMouse>", 'xt')
call assert_equal(13, g:got_mouse_col)
call assert_equal(3, g:got_mouse_lnum)
call assert_equal(winid, g:got_mouse_winid)
call assert_equal(item.result, g:got_mousepos)
endfor
call popup_close(winid)
enew!
delfunc MyPopupFilter
endfunc

View File

@@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2304,
/**/
2303,
/**/