To: vim_dev@googlegroups.com Subject: Patch 8.1.2304 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.2304 Problem: Cannot get the mouse position when getting a mouse click. Solution: Add getmousepos(). Files: runtime/doc/eval.txt, runtime/doc/popup.txt, src/mouse.c src/proto/mouse.pro, src/evalfunc.c, src/popupwin.c, src/popupwin.pro, src/testdir/test_popupwin.vim, src/testdir/test_functions.vim *** ../vim-8.1.2303/runtime/doc/eval.txt 2019-10-29 04:12:38.620582834 +0100 --- runtime/doc/eval.txt 2019-11-16 18:20:29.431251620 +0100 *************** *** 2480,2485 **** --- 2480,2486 ---- 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 *************** *** 4912,4919 **** 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: > let c = getchar() if c == "\" && v:mouse_win > 0 exe v:mouse_win . "wincmd w" --- 4919,4927 ---- 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|. ! |getmousepos()| can also be used. This example positions the ! mouse as it would normally happen: > let c = getchar() if c == "\" && v:mouse_win > 0 exe v:mouse_win . "wincmd w" *************** *** 5323,5328 **** --- 5331,5365 ---- '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 *** ../vim-8.1.2303/runtime/doc/popup.txt 2019-11-11 21:45:01.925407125 +0100 --- runtime/doc/popup.txt 2019-11-16 15:57:02.558631367 +0100 *************** *** 862,871 **** cursor keys select another entry Tab accept current suggestion ! A mouse click arrives as . 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). Vim provides standard filters |popup_filter_menu()| and |popup_filter_yesno()|. --- 862,869 ---- cursor keys select another entry Tab accept current suggestion ! A mouse click arrives as . The coordinates can be obtained with ! |mousegetpos()|. Vim provides standard filters |popup_filter_menu()| and |popup_filter_yesno()|. *** ../vim-8.1.2303/src/mouse.c 2019-11-13 22:35:15.759521804 +0100 --- src/mouse.c 2019-11-16 18:12:11.385526875 +0100 *************** *** 2822,2827 **** --- 2822,2828 ---- int retval = FALSE; int off; int count; + char_u *p; #ifdef FEAT_RIGHTLEFT if (win->w_p_rl) *************** *** 2881,2886 **** --- 2882,2892 ---- 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,3003 **** --- 3007,3067 ---- 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 *** ../vim-8.1.2303/src/proto/mouse.pro 2019-09-23 21:16:51.387544361 +0200 --- src/proto/mouse.pro 2019-11-16 16:20:57.037027736 +0100 *************** *** 17,20 **** --- 17,21 ---- 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 : */ *** ../vim-8.1.2303/src/evalfunc.c 2019-11-10 00:13:46.434916175 +0100 --- src/evalfunc.c 2019-11-16 16:08:14.380168924 +0100 *************** *** 465,470 **** --- 465,471 ---- {"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}, *** ../vim-8.1.2303/src/popupwin.c 2019-11-13 22:35:15.755521778 +0100 --- src/popupwin.c 2019-11-16 16:52:16.180901037 +0100 *************** *** 1047,1052 **** --- 1047,1061 ---- } /* + * 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,2940 **** 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; --- 2917,2928 ---- *** ../vim-8.1.2303/src/testdir/test_popupwin.vim 2019-11-13 22:35:15.759521804 +0100 --- src/testdir/test_popupwin.vim 2019-11-16 18:12:59.365307098 +0100 *************** *** 2205,2246 **** 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 return 0 endfunc ! let winid = popup_create(['short', 'long line that will wrap', 'short'], #{ ! \ line: 4, ! \ col: 8, \ maxwidth: 12, \ filter: 'MyPopupFilter', \ }) redraw ! call test_setmouse(4, 8) ! call feedkeys("\", '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("\", 'xt') ! call assert_equal(1, g:got_mouse_col) ! call assert_equal(2, g:got_mouse_lnum) ! ! call test_setmouse(6, 8) ! call feedkeys("\", 'xt') ! call assert_equal(13, g:got_mouse_col) ! call assert_equal(2, g:got_mouse_lnum) ! ! call test_setmouse(7, 20) ! call feedkeys("\", '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 popup_close(winid) delfunc MyPopupFilter endfunc --- 2205,2310 ---- func Test_popupwin_filter_mouse() func MyPopupFilter(winid, c) ! let g:got_mousepos = getmousepos() return 0 endfunc ! 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 ! " 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 ! ! " 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("\", 'xt') ! call assert_equal(item.result, g:got_mousepos) ! endfor call popup_close(winid) + enew! delfunc MyPopupFilter endfunc *** ../vim-8.1.2303/src/testdir/test_functions.vim 2019-09-28 22:11:49.654184756 +0200 --- src/testdir/test_functions.vim 2019-11-16 18:18:14.083868933 +0100 *************** *** 1331,1336 **** --- 1331,1337 ---- 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,1347 **** --- 1343,1349 ---- 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() *** ../vim-8.1.2303/src/version.c 2019-11-16 14:19:29.715739224 +0100 --- src/version.c 2019-11-16 18:08:02.754668833 +0100 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 2304, /**/ -- From "know your smileys": |-P Reaction to unusually ugly C code /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///