diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 0ef255210b8820..0ecce514ac8ccf 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -10523,7 +10523,10 @@ A jump table for the options with a short description can be found at |Q_op|. is not supported for file and directory names and instead wildcard expansion is used. pum Display the completion matches using the popup menu in - the same style as the |ins-completion-menu|. + the same style as the |ins-completion-menu|. When an + info popup is shown next to the menu, it can be + scrolled by moving the mouse pointer on top of it and + using the scroll wheel. tagfile When using CTRL-D to list matching tags, the kind of tag and the file of the tag is listed. Only one match is displayed per line. Often used tag kinds are: diff --git a/src/ex_getln.c b/src/ex_getln.c index 7e26d6cdb4f456..ea20fa96b8ff98 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -2064,12 +2064,15 @@ getcmdline_int( // navigating the wild menu (i.e. the key is not 'wildchar' or // 'wildcharm' or Ctrl-N or Ctrl-P or Ctrl-A or Ctrl-L). // If the popup menu is displayed, then PageDown and PageUp keys are - // also used to navigate the menu. + // also used to navigate the menu, and the mouse scroll wheel keys + // scroll the info popup. end_wildmenu = (!key_is_wc && c != Ctrl_N && c != Ctrl_P && c != Ctrl_A && c != Ctrl_L); end_wildmenu = end_wildmenu && (!cmdline_pum_active() || (c != K_PAGEDOWN && c != K_PAGEUP - && c != K_KPAGEDOWN && c != K_KPAGEUP)); + && c != K_KPAGEDOWN && c != K_KPAGEUP + && c != K_MOUSEDOWN && c != K_MOUSEUP + && c != K_MOUSELEFT && c != K_MOUSERIGHT)); // free expanded names when finished walking through matches if (end_wildmenu) @@ -2413,11 +2416,21 @@ getcmdline_int( cmdline_left_right_mouse(c, &ignore_drag_release); goto cmdline_not_changed; - // Mouse scroll wheel: ignored here + // Mouse scroll wheel: scroll the completion info popup when the mouse + // is on top of it, otherwise ignored here. case K_MOUSEDOWN: case K_MOUSEUP: case K_MOUSELEFT: case K_MOUSERIGHT: +#ifdef FEAT_PROP_POPUP + if (cmdline_pum_active()) + cmdline_mousescroll(c == K_MOUSEDOWN ? MSCR_DOWN + : c == K_MOUSEUP ? MSCR_UP + : c == K_MOUSELEFT ? MSCR_LEFT + : MSCR_RIGHT); +#endif + goto cmdline_not_changed; + // Alternate buttons ignored here case K_X1MOUSE: case K_X1DRAG: diff --git a/src/mouse.c b/src/mouse.c index ddd94fffcf0e1f..9080334e7113b5 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -1396,6 +1396,62 @@ ins_mousescroll(int dir) } } +#if defined(FEAT_PROP_POPUP) || defined(PROTO) +/* + * Command-line mode implementation for scrolling in direction "dir", which is + * one of the MSCR_ values. Scrolls the completion info popup when the mouse + * pointer is on top of it. + * Returns TRUE when the info popup was scrolled. + */ + int +cmdline_mousescroll(int dir) +{ + cmdarg_T cap; + oparg_T oa; + + CLEAR_FIELD(cap); + clear_oparg(&oa); + cap.oap = &oa; + cap.arg = dir; + + switch (dir) + { + case MSCR_UP: cap.cmdchar = K_MOUSEUP; break; + case MSCR_DOWN: cap.cmdchar = K_MOUSEDOWN; break; + case MSCR_LEFT: cap.cmdchar = K_MOUSELEFT; break; + case MSCR_RIGHT: cap.cmdchar = K_MOUSERIGHT; break; + } + + if (mouse_row < 0 || mouse_col < 0) + return FALSE; + + int row = mouse_row; + int col = mouse_col; + win_T *wp; + + // Only scroll when the mouse is on top of the info popup. + wp = mouse_find_win(&row, &col, FIND_POPUP); + if (wp == NULL || !WIN_IS_POPUP(wp) || !(wp->w_popup_flags & POPF_INFO) + || !wp->w_has_scrollbar) + return FALSE; + + win_T *old_curwin = curwin; + + curwin = wp; + curbuf = wp->w_buffer; + // Call the common mouse scroll function shared with other modes. + do_mousescroll(&cap); + curwin = old_curwin; + curbuf = curwin->w_buffer; + + // Cmdline mode doesn't normally call update_screen(), so redraw the + // completion popup menu, which also repaints the info popup. + if (cmdline_pum_active()) + cmdline_pum_display(); + return TRUE; +} +#endif + /* * Return TRUE if "c" is a mouse key. */ diff --git a/src/proto/mouse.pro b/src/proto/mouse.pro index ead81849851ba3..0c320769ba1b81 100644 --- a/src/proto/mouse.pro +++ b/src/proto/mouse.pro @@ -4,6 +4,7 @@ void mouse_set_hor_scroll_step(long step); int do_mouse(oparg_T *oap, int c, int dir, long count, int fixindent); void ins_mouse(int c); void ins_mousescroll(int dir); +int cmdline_mousescroll(int dir); int is_mouse_key(int c); int get_mouse_button(int code, int *is_click, int *is_drag); int get_pseudo_mouse_code(int button, int is_click, int is_drag); diff --git a/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_1.dump b/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_1.dump new file mode 100644 index 00000000000000..dc622d74ab2a6f --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_1.dump @@ -0,0 +1,12 @@ +| +0&#ffffff0@23|╔+0#0000001#e0e0e08|═@14|X| +0#0000000#ffffff0@33 +|~+0#4040ff13&| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1| @1| +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |2| @1| +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |3| @1| +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |4| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |5| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |6| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |7| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |8| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @6| +0#0000001#e0e0e08|a|p@1|l|e| @1|f| |f|r|u|i|t| |║| |i|n|f|o| |l|i|n|e| |9| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @6| +0#0000001#ffd7ff255|b|a|n|a|n|a| |f| |f|r|u|i|t| |╚+0&#e0e0e08|═@14|⇲| +0#4040ff13#ffffff0@33 +|:+0#0000000&|D|i|c|t|C|m|d| |a|p@1|l|e> @60 diff --git a/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_2.dump b/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_2.dump new file mode 100644 index 00000000000000..115b1b949ee2f8 --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_2.dump @@ -0,0 +1,12 @@ +| +0&#ffffff0@23|╔+0#0000001#e0e0e08|═@14|X| +0#0000000#ffffff0@33 +|~+0#4040ff13&| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|0| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1@1| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|2| | +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|3| | +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|4| | +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|5| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|6| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|7| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @6| +0#0000001#e0e0e08|a|p@1|l|e| @1|f| |f|r|u|i|t| |║| |i|n|f|o| |l|i|n|e| |1|8| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @6| +0#0000001#ffd7ff255|b|a|n|a|n|a| |f| |f|r|u|i|t| |╚+0&#e0e0e08|═@14|⇲| +0#4040ff13#ffffff0@33 +|:+0#0000000&|D|i|c|t|C|m|d| |a|p@1|l|e> @42|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_3.dump b/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_3.dump new file mode 100644 index 00000000000000..1a0c4fbcbb63ae --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_info_mouse_scroll_3.dump @@ -0,0 +1,12 @@ +| +0&#ffffff0@23|╔+0#0000001#e0e0e08|═@14|X| +0#0000000#ffffff0@33 +|~+0#4040ff13&| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |4| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |5| @1| +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |6| @1| +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |7| @1| +0#0000000#0000001|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |8| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |9| @1| +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1|0| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @22|║+0#0000001#e0e0e08| |i|n|f|o| |l|i|n|e| |1@1| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @6| +0#0000001#e0e0e08|a|p@1|l|e| @1|f| |f|r|u|i|t| |║| |i|n|f|o| |l|i|n|e| |1|2| | +0#0000000#a8a8a8255|║+0#0000001#e0e0e08| +0#4040ff13#ffffff0@33 +|~| @6| +0#0000001#ffd7ff255|b|a|n|a|n|a| |f| |f|r|u|i|t| |╚+0&#e0e0e08|═@14|⇲| +0#4040ff13#ffffff0@33 +|:+0#0000000&|D|i|c|t|C|m|d| |a|p@1|l|e> @42|0|,|0|-|1| @8|A|l@1| diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 31fb1f8ffc8cff..8fbaa502b8abd4 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -4768,6 +4768,52 @@ func Test_customlist_dict_completion_info_popup() call StopVimInTerminal(buf) endfunc +" Test that the mouse scroll wheel scrolls the info popup of the command line +" completion popup menu when the mouse pointer is on top of it. +func Test_wildmenu_pum_info_mouse_scroll() + CheckScreendump + CheckFeature quickfix + + let lines =<< trim END + func DictComp(A, L, P) + let info = join(map(range(1, 30), '"info line " .. v:val'), "\n") + return [ + \ {'word': 'apple', 'kind': 'f', 'menu': 'fruit', 'info': info}, + \ {'word': 'banana', 'kind': 'f', 'menu': 'fruit', 'info': info}, + \ ] + endfunc + command -nargs=1 -complete=customlist,DictComp DictCmd echo + set wildmenu wildoptions=pum completeopt=menu,popup mouse=a + + " Put the mouse on top of the info popup and turn the scroll wheel. + func ScrollInfo(keys) + let pos = popup_getpos(popup_findinfo()) + call test_setmouse(pos.line + 1, pos.col + 1) + call feedkeys(a:keys, 'nt') + endfunc + cnoremap call ScrollInfo(repeat("\", 3)) + cnoremap call ScrollInfo(repeat("\", 2)) + END + call writefile(lines, 'XtestWildmenuMouseScroll', 'D') + let buf = RunVimInTerminal('-S XtestWildmenuMouseScroll', #{rows: 12}) + + " The info popup is shown next to the completion popup menu. + call term_sendkeys(buf, ":DictCmd \") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_info_mouse_scroll_1', {}) + + " Scrolling down with the wheel scrolls the info popup without closing the + " completion popup menu. + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_info_mouse_scroll_2', {}) + + " Scrolling back up scrolls the info popup up again. + call term_sendkeys(buf, "\") + call VerifyScreenDump(buf, 'Test_wildmenu_pum_info_mouse_scroll_3', {}) + + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) +endfunc + func Test_cmdline_complete_findfunc_dict() CheckScreendump