From 76fdd9b882489b233ca00a0809d719c70e48b164 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 10 Nov 2025 07:07:25 +0800 Subject: [PATCH] fix(pum): crash when resizing grid with pumborder set (#36404) Problem: Grid size check didn't account for border_width, causing row index out of bounds when drawing bordered popup menu. Solution: Check grid.rows against pum_height + border_width. --- src/nvim/popupmenu.c | 3 ++- test/functional/ui/popupmenu_spec.lua | 34 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index f182744631..3b96ebda00 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -660,7 +660,8 @@ void pum_redraw(void) 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 + border_width + || pum_grid.cols != grid_width + border_width) { grid_alloc(&pum_grid, pum_height + border_width, grid_width + border_width, !invalid_grid, false); ui_call_grid_resize(pum_grid.handle, pum_grid.cols, pum_grid.rows); diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 8f93474839..0fb0c70e71 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -14,6 +14,7 @@ local eq = t.eq local pcall_err = t.pcall_err local exec_lua = n.exec_lua local exec = n.exec +local poke_eventloop = n.poke_eventloop describe('ui/ext_popupmenu', function() local screen @@ -9343,6 +9344,39 @@ describe('builtin popupmenu', function() ]]) end end) + it("no crash when 'pumborder' set #36337", function() + command('set autocomplete pumborder=rounded complete=o cot=popup,menuone,noinsert') + command('set columns=50 lines=20') + exec_lua(function() + local list1 = { + { abbr = 'array: ', info = '', kind = 'Field', word = 'array: ' }, + { abbr = 'arrays: ', info = '', kind = 'Field', word = 'arrays: ' }, + } + local list2 = { + { abbr = 'match ', info = '', kind = 'Keyword', word = 'match ' }, + { abbr = 'throw ', info = '', kind = 'Keyword', word = 'throw ' }, + { abbr = 'array: ', info = '', kind = 'Field', word = 'array: ' }, + { abbr = 'arrays: ', info = '', kind = 'Field', word = 'arrays: ' }, + } + _G.fake_omni = function(_, _) + local line = vim.api.nvim_get_current_line() + if line:find('%s%)$') then + vim.schedule(function() + vim.fn.complete(25, list1) + vim.fn.complete(25, list2) + end) + end + return -2 + end + vim.opt.omnifunc = 'v:lua.fake_omni' + vim.api.nvim_buf_set_lines(0, 0, -1, true, { '