From a7550a20e0c3084eacd2b4ede1e6a94f282c2fb8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 10 Jan 2024 12:56:43 +0800 Subject: [PATCH] fix(pum): handle right-click menu repositioning with multigrid (#26975) --- src/nvim/popupmenu.c | 23 ++++++---- test/functional/ui/popupmenu_spec.lua | 65 ++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index f3cc804097..220214c887 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -58,7 +58,8 @@ static bool pum_rl; // true when popupmenu is drawn 'rightleft' static int pum_anchor_grid; // grid where position is defined static int pum_row; // top row of pum -static int pum_col; // left column of pum +static int pum_col; // left column of pum, right column if 'rightleft' +static int pum_left_col; // left column of pum, before padding or scrollbar static bool pum_above; // pum is drawn above cursor line static bool pum_is_visible = false; @@ -464,14 +465,14 @@ void pum_redraw(void) grid_assign_handle(&pum_grid); - bool moved = ui_comp_put_grid(&pum_grid, pum_row, pum_col - col_off, + pum_left_col = pum_col - col_off; + bool moved = ui_comp_put_grid(&pum_grid, pum_row, pum_left_col, pum_height, grid_width, false, true); bool invalid_grid = moved || pum_invalid; pum_invalid = false; must_redraw_pum = false; - if (!pum_grid.chars - || pum_grid.rows != pum_height || pum_grid.cols != grid_width) { + if (!pum_grid.chars || pum_grid.rows != pum_height || pum_grid.cols != grid_width) { grid_alloc(&pum_grid, pum_height, grid_width, !invalid_grid, false); ui_call_grid_resize(pum_grid.handle, pum_grid.cols, pum_grid.rows); } else if (invalid_grid) { @@ -480,9 +481,8 @@ void pum_redraw(void) if (ui_has(kUIMultigrid)) { const char *anchor = pum_above ? "SW" : "NW"; int row_off = pum_above ? -pum_height : 0; - ui_call_win_float_pos(pum_grid.handle, -1, cstr_as_string((char *)anchor), - pum_anchor_grid, pum_row - row_off, pum_col - col_off, - false, pum_grid.zindex); + ui_call_win_float_pos(pum_grid.handle, -1, cstr_as_string((char *)anchor), pum_anchor_grid, + pum_row - row_off, pum_left_col, false, pum_grid.zindex); } // Never display more than we have @@ -1160,7 +1160,14 @@ static void pum_position_at_mouse(int min_width) max_col = MAX(Columns - wp->w_wincol, wp->w_grid.cols); } } - pum_anchor_grid = mouse_grid; + if (pum_grid.handle != 0 && mouse_grid == pum_grid.handle) { + // Repositioning the menu by right-clicking on itself + mouse_grid = pum_anchor_grid; + mouse_row += pum_row; + mouse_col += pum_left_col; + } else { + pum_anchor_grid = mouse_grid; + } if (max_row - mouse_row > pum_size) { // Enough space below the mouse row. pum_above = false; diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 67a5f2ef77..da0a68edcb 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -3770,6 +3770,67 @@ describe('builtin popupmenu', function() :let g:menustr = 'b{n: baz } | ]]) end + if multigrid then + meths.input_mouse('right', 'press', '', 2, 0, 18) + screen:expect { + grid = [[ + ## grid 1 + [2:--------------------------------]|*5 + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }|*4 + ## grid 3 + :let g:menustr = 'bar' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], + float_pos = { + [4] = { { id = -1 }, 'NW', 2, 1, 17, false, 250 }, + }, + } + else + feed('<18,0>') + screen:expect([[ + ^popup menu test | + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + {1:~ }{n: baz }{1: }| + {1:~ }| + :let g:menustr = 'bar' | + ]]) + end + if multigrid then + meths.input_mouse('right', 'press', '', 4, 1, 3) + screen:expect({ + grid = [[ + ## grid 1 + [2:--------------------------------]|*5 + [3:--------------------------------]| + ## grid 2 + ^popup menu test | + {1:~ }|*4 + ## grid 3 + :let g:menustr = 'bar' | + ## grid 4 + {n: foo }| + {n: bar }| + {n: baz }| + ]], + float_pos = { [4] = { { id = -1 }, 'NW', 2, 3, 19, false, 250 } }, + }) + else + feed('<20,2>') + screen:expect([[ + ^popup menu test | + {1:~ }|*2 + {1:~ }{n: foo }{1: }| + {1:~ }{n: bar }{1: }| + :let g:menustr = 'b{n: baz } | + ]]) + end if multigrid then meths.input_mouse('left', 'press', '', 4, 2, 2) screen:expect({ @@ -3785,7 +3846,7 @@ describe('builtin popupmenu', function() ]], }) else - feed('<22,5>') + feed('<21,5>') screen:expect([[ ^popup menu test | {1:~ }|*4 @@ -4022,7 +4083,7 @@ describe('builtin popupmenu', function() ]], }) else - feed('<22,3>') + feed('<21,3>') screen:expect([[ popup menu test | {1:~ }|