mirror of
https://github.com/neovim/neovim.git
synced 2026-03-28 03:12:00 +00:00
fix(ui): apply 'pumborder' to mouse menu, fix overflow #36193
Problem: Mouse popup menus (right-click context menus) do not respect the 'pumborder' option and could overflow screen boundaries when borders were enabled near the edge. Solution: - Remove the mouse menu exclusion from border rendering. - Add boundary check to shift menu left when border would exceed screen width, ensuring complete visibility of menu content and borders.
This commit is contained in:
@@ -4903,6 +4903,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
valid values. |hl-PmenuBorder| is used for highlighting the border, and when
|
||||
style is "shadow" the |hl-PmenuShadow| and |hl-PmenuShadowThrough| groups are used.
|
||||
|
||||
This option also applies to mouse popup menus when 'mousemodel' is set to
|
||||
"popup" or "popup_setpos", which will display borders using the same style.
|
||||
|
||||
*'pumheight'* *'ph'*
|
||||
'pumheight' 'ph' number (default 0)
|
||||
global
|
||||
|
||||
3
runtime/lua/vim/_meta/options.lua
generated
3
runtime/lua/vim/_meta/options.lua
generated
@@ -5108,6 +5108,9 @@ vim.go.pb = vim.go.pumblend
|
||||
--- valid values. `hl-PmenuBorder` is used for highlighting the border, and when
|
||||
--- style is "shadow" the `hl-PmenuShadow` and `hl-PmenuShadowThrough` groups are used.
|
||||
---
|
||||
--- This option also applies to mouse popup menus when 'mousemodel' is set to
|
||||
--- "popup" or "popup_setpos", which will display borders using the same style.
|
||||
---
|
||||
--- @type string
|
||||
vim.o.pumborder = ""
|
||||
vim.go.pumborder = vim.o.pumborder
|
||||
|
||||
@@ -6699,6 +6699,9 @@ local options = {
|
||||
Defines the default border style of popupmenu windows. See 'winborder' for
|
||||
valid values. |hl-PmenuBorder| is used for highlighting the border, and when
|
||||
style is "shadow" the |hl-PmenuShadow| and |hl-PmenuShadowThrough| groups are used.
|
||||
|
||||
This option also applies to mouse popup menus when 'mousemodel' is set to
|
||||
"popup" or "popup_setpos", which will display borders using the same style.
|
||||
]=],
|
||||
short_desc = N_('border of popupmenu'),
|
||||
type = 'string',
|
||||
|
||||
@@ -679,10 +679,7 @@ void pum_redraw(void)
|
||||
}
|
||||
|
||||
int scroll_range = pum_size - pum_height;
|
||||
|
||||
// avoid set border for mouse menu
|
||||
int mouse_menu = State != MODE_CMDLINE && pum_grid.zindex == kZIndexCmdlinePopupMenu;
|
||||
if (!mouse_menu && fconfig.border) {
|
||||
if (fconfig.border) {
|
||||
grid_draw_border(&pum_grid, &fconfig, NULL, 0, NULL);
|
||||
if (!fconfig.shadow) {
|
||||
row++;
|
||||
@@ -1437,18 +1434,21 @@ static void pum_position_at_mouse(int min_width)
|
||||
pum_anchor_grid = grid;
|
||||
}
|
||||
|
||||
if (max_row - row > pum_size || max_row - row > row - min_row) {
|
||||
// Both width and height are 1 for shadow border, otherwise 2
|
||||
int border_width = pum_border_width();
|
||||
int border_height = border_width;
|
||||
if (max_row - row > pum_size + border_height || max_row - row > row - min_row) {
|
||||
// Enough space below the mouse row,
|
||||
// or there is more space below the mouse row than above.
|
||||
pum_above = false;
|
||||
pum_row = row + 1;
|
||||
if (pum_height > max_row - pum_row) {
|
||||
pum_height = max_row - pum_row;
|
||||
if (pum_height + border_height > max_row - pum_row) {
|
||||
pum_height = max_row - pum_row - border_height;
|
||||
}
|
||||
} else {
|
||||
// Show above the mouse row, reduce height if it does not fit.
|
||||
pum_above = true;
|
||||
pum_row = row - pum_size;
|
||||
pum_row = row - pum_size - border_height;
|
||||
if (pum_row < min_row) {
|
||||
pum_height += pum_row - min_row;
|
||||
pum_row = min_row;
|
||||
@@ -1456,25 +1456,25 @@ static void pum_position_at_mouse(int min_width)
|
||||
}
|
||||
|
||||
if (pum_rl) {
|
||||
if (col - min_col + 1 >= pum_base_width
|
||||
|| col - min_col + 1 > min_width) {
|
||||
if (col - min_col + 1 >= pum_base_width + border_width
|
||||
|| col - min_col + 1 > min_width + border_width) {
|
||||
// Enough space to show at mouse column.
|
||||
pum_col = col;
|
||||
} else {
|
||||
// Not enough space, left align with window.
|
||||
pum_col = min_col + MIN(pum_base_width, min_width) - 1;
|
||||
pum_col = min_col + MIN(pum_base_width + border_width, min_width + border_width) - 1;
|
||||
}
|
||||
pum_width = pum_col - min_col + 1;
|
||||
pum_width = pum_col - min_col + 1 - border_width;
|
||||
} else {
|
||||
if (max_col - col >= pum_base_width
|
||||
|| max_col - col > min_width) {
|
||||
if (max_col - col >= pum_base_width + border_width
|
||||
|| max_col - col > min_width + border_width) {
|
||||
// Enough space to show at mouse column.
|
||||
pum_col = col;
|
||||
} else {
|
||||
// Not enough space, right align with window.
|
||||
pum_col = max_col - MIN(pum_base_width, min_width);
|
||||
pum_col = max_col - MIN(pum_base_width + border_width, min_width + border_width);
|
||||
}
|
||||
pum_width = max_col - pum_col;
|
||||
pum_width = max_col - pum_col - border_width;
|
||||
}
|
||||
|
||||
pum_width = MIN(pum_width, pum_base_width + 1);
|
||||
@@ -1492,7 +1492,10 @@ static void pum_select_mouse_pos(void)
|
||||
}
|
||||
|
||||
if (grid == pum_grid.handle) {
|
||||
pum_selected = row;
|
||||
// Offset by 1 when border width is 2 (non-shadow border)
|
||||
int border_offset = pum_border_width() == 2 ? 1 : 0;
|
||||
int item = row - border_offset;
|
||||
pum_selected = (item >= 0 && item < pum_height) ? item : -1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9398,6 +9398,146 @@ describe('builtin popupmenu', function()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
it("'pumborder' on mouse-menu displays completely within screen", function()
|
||||
screen:try_resize(40, 12)
|
||||
command('set pumborder=rounded')
|
||||
-- Click near right edge to test boundary handling
|
||||
if send_mouse_grid then
|
||||
api.nvim_input_mouse('right', 'press', '', 2, 2, 35)
|
||||
else
|
||||
feed('<RightMouse><35,2>')
|
||||
end
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
[2:----------------------------------------]|*11
|
||||
[3:----------------------------------------]|
|
||||
## grid 2
|
||||
^ |
|
||||
{1:~ }|*10
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
{n:╭─────────────────────╮}|
|
||||
{n:│ Inspect │}|
|
||||
{n:│ │}|
|
||||
{n:│ Paste │}|
|
||||
{n:│ Select All │}|
|
||||
{n:│ │}|
|
||||
{n:│ How-to disable mouse│}|
|
||||
{n:╰─────────────────────╯}|
|
||||
]],
|
||||
float_pos = {
|
||||
[4] = { -1, 'NW', 2, 3, 17, false, 250, 2, 3, 17 },
|
||||
},
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*2
|
||||
{1:~ }{n:╭─────────────────────╮}|
|
||||
{1:~ }{n:│ Inspect │}|
|
||||
{1:~ }{n:│ │}|
|
||||
{1:~ }{n:│ Paste │}|
|
||||
{1:~ }{n:│ Select All │}|
|
||||
{1:~ }{n:│ │}|
|
||||
{1:~ }{n:│ How-to disable mouse│}|
|
||||
{1:~ }{n:╰─────────────────────╯}|
|
||||
|
|
||||
]])
|
||||
end
|
||||
if send_mouse_grid then
|
||||
api.nvim_input_mouse('move', '', '', 4, 1, 1)
|
||||
else
|
||||
feed('<MouseMove><25,4>')
|
||||
end
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
[2:----------------------------------------]|*11
|
||||
[3:----------------------------------------]|
|
||||
## grid 2
|
||||
^ |
|
||||
{1:~ }|*10
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
{n:╭─────────────────────╮}|
|
||||
{n:│}{12: Inspect }{n:│}|
|
||||
{n:│ │}|
|
||||
{n:│ Paste │}|
|
||||
{n:│ Select All │}|
|
||||
{n:│ │}|
|
||||
{n:│ How-to disable mouse│}|
|
||||
{n:╰─────────────────────╯}|
|
||||
]],
|
||||
float_pos = {
|
||||
[4] = { -1, 'NW', 2, 3, 17, false, 250, 2, 3, 17 },
|
||||
},
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
^ |
|
||||
{1:~ }|*2
|
||||
{1:~ }{n:╭─────────────────────╮}|
|
||||
{1:~ }{n:│}{12: Inspect }{n:│}|
|
||||
{1:~ }{n:│ │}|
|
||||
{1:~ }{n:│ Paste │}|
|
||||
{1:~ }{n:│ Select All │}|
|
||||
{1:~ }{n:│ │}|
|
||||
{1:~ }{n:│ How-to disable mouse│}|
|
||||
{1:~ }{n:╰─────────────────────╯}|
|
||||
|
|
||||
]])
|
||||
end
|
||||
-- when right-clicking on the bottom menu, it should appear above the mouse_row
|
||||
if send_mouse_grid then
|
||||
api.nvim_input_mouse('right', 'press', '', 2, 8, 20)
|
||||
else
|
||||
feed('<RightMouse><20,8>')
|
||||
end
|
||||
if multigrid then
|
||||
screen:expect({
|
||||
grid = [[
|
||||
## grid 1
|
||||
[2:----------------------------------------]|*11
|
||||
[3:----------------------------------------]|
|
||||
## grid 2
|
||||
^ |
|
||||
{1:~ }|*10
|
||||
## grid 3
|
||||
|
|
||||
## grid 4
|
||||
{n:╭─────────────────────╮}|
|
||||
{n:│ Inspect │}|
|
||||
{n:│ │}|
|
||||
{n:│ Paste │}|
|
||||
{n:│ Select All │}|
|
||||
{n:│ │}|
|
||||
{n:│ How-to disable mouse│}|
|
||||
{n:╰─────────────────────╯}|
|
||||
]],
|
||||
float_pos = {
|
||||
[4] = { -1, 'SW', 2, 6, 17, false, 250, 2, 0, 17 },
|
||||
},
|
||||
})
|
||||
else
|
||||
screen:expect([[
|
||||
^ {n:╭─────────────────────╮}|
|
||||
{1:~ }{n:│ Inspect │}|
|
||||
{1:~ }{n:│ │}|
|
||||
{1:~ }{n:│ Paste │}|
|
||||
{1:~ }{n:│ Select All │}|
|
||||
{1:~ }{n:│ │}|
|
||||
{1:~ }{n:│ How-to disable mouse│}|
|
||||
{1:~ }{n:╰─────────────────────╯}|
|
||||
{1:~ }|*3
|
||||
|
|
||||
]])
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
describe('with ext_multigrid and actual mouse grid', function()
|
||||
|
||||
Reference in New Issue
Block a user