summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-11-16 18:22:41 +0100
committerBram Moolenaar <Bram@vim.org>2019-11-16 18:22:41 +0100
commitdb3a205147ce2c335d5c2181c1f789277f8775b0 (patch)
tree1bb6a6d5158fee1d79718053ffa167396acf2970
parent08f23636aef595f4cc061dfee8248dca97df16b3 (diff)
downloadvim-git-8.1.2304.tar.gz
patch 8.1.2304: cannot get the mouse position when getting a mouse clickv8.1.2304
Problem: Cannot get the mouse position when getting a mouse click. Solution: Add getmousepos().
-rw-r--r--runtime/doc/eval.txt39
-rw-r--r--runtime/doc/popup.txt6
-rw-r--r--src/evalfunc.c1
-rw-r--r--src/mouse.c64
-rw-r--r--src/popupwin.c30
-rw-r--r--src/proto/mouse.pro1
-rw-r--r--src/testdir/test_functions.vim2
-rw-r--r--src/testdir/test_popupwin.vim116
-rw-r--r--src/version.c2
9 files changed, 204 insertions, 57 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 9ba53887b..9bac54e99 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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
diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt
index 39e4a3ce8..bdd827281 100644
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -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()|.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index e5be36140..945c5f227 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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},
diff --git a/src/mouse.c b/src/mouse.c
index 3e1741f98..f215d3d99 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -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
diff --git a/src/popupwin.c b/src/popupwin.c
index ed04645ea..48c017f67 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -1047,6 +1047,15 @@ popup_top_extra(win_T *wp)
}
/*
+ * 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.
*/
int
@@ -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;
diff --git a/src/proto/mouse.pro b/src/proto/mouse.pro
index 3faf056d9..f2a8c3829 100644
--- a/src/proto/mouse.pro
+++ b/src/proto/mouse.pro
@@ -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 : */
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index 4f39d875d..e7b81daf4 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -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()
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index 44e18197c..041d83465 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -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)
-
- 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)
-
- 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)
+ " 123456789012345678901
+ " 1 .....................
+ " 2 ...+--------------+..
+ " 3 ...| |..
+ " 4 ...| short |..
+ " 5 ...| long line th |..
+ " 6 ...| at will wrap |..
+ " 7 ...| other |..
+ " 8 ...| |..
+ " 9 ...+--------------+..
+ " 10 .....................
+ let tests = []
+
+ 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(7, 20)
- 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)
+ " 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)
+
+ for item in tests
+ call test_setmouse(item.clickrow, item.clickcol)
+ call feedkeys("\<LeftMouse>", 'xt')
+ call assert_equal(item.result, g:got_mousepos)
+ endfor
call popup_close(winid)
+ enew!
delfunc MyPopupFilter
endfunc
diff --git a/src/version.c b/src/version.c
index 5d97575c4..b08106c01 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2304,
+/**/
2303,
/**/
2302,