]> granicus.if.org Git - vim/commitdiff
patch 8.1.2304: cannot get the mouse position when getting a mouse click v8.1.2304
authorBram Moolenaar <Bram@vim.org>
Sat, 16 Nov 2019 17:22:41 +0000 (18:22 +0100)
committerBram Moolenaar <Bram@vim.org>
Sat, 16 Nov 2019 17:22:41 +0000 (18:22 +0100)
Problem:    Cannot get the mouse position when getting a mouse click.
Solution:   Add getmousepos().

runtime/doc/eval.txt
runtime/doc/popup.txt
src/evalfunc.c
src/mouse.c
src/popupwin.c
src/proto/mouse.pro
src/testdir/test_functions.vim
src/testdir/test_popupwin.vim
src/version.c

index 9ba53887be7972deb4f52c5d67d9667483df7dd8..9bac54e990fa64edc1476d506b4179bcc9b9b04f 100644 (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
index 39e4a3ce8369a3e2a6f59208f50c05100d7e07db..bdd8272811336f817fd88dc5afa19f4691c80dfe 100644 (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()|.
index e5be361406c52d7df2f0a5221ab9e2e124e4466b..945c5f227f213e1336f753ba55048deaae54a79b 100644 (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},
index 3e1741f9838e812a787d8c6a6c12cf1c03297818..f215d3d99640faca8d30b81af5dd48ed4cff6850 100644 (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
index ed04645ea10ba4a7ab17f087359362bc4810e76b..48c017f67f2ee8ca9c0dc3f4bc797f428d5b4660 100644 (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;
index 3faf056d9491a058774c1200022c1d133d4105ba..f2a8c3829cee6246e2125570bc56df40b500b5c6 100644 (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 : */
index 4f39d875d93d818d440e7563516c2207c67fb192..e7b81daf4bb80cb84263d27c1052865453149478 100644 (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()
index 44e18197c600877a7f5cbace5fff761cb99f06b1..041d834652d11145c7b064b9a25371c3b15702b4 100644 (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)
-
-  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
 
index 5d97575c4f80aeccc4f2af0c9083a8d115b1250c..b08106c014a02f441ea95d937eb5ad084fe61280 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2304,
 /**/
     2303,
 /**/