From d87972f9200081393d49895718c0a60a2462d7ba Mon Sep 17 00:00:00 2001 From: glepnir Date: Thu, 12 Mar 2026 17:48:14 +0800 Subject: [PATCH] fix(pum): keep info window aligned with pum when above #38251 Problem: When `pum_above` is set, the info window uses `anchor=SW`. Updating the info window height during `CompleteChanged` causes its top edge to shift, so it no longer aligns with the top of the pum. Solution: Use `NW` as the anchor even when `pum_above` is true so the info window remains aligned with `pum_row`. --- src/nvim/popupmenu.c | 5 +-- test/functional/ui/popupmenu_spec.lua | 56 ++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index defc67c6b7..8091621c02 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -1003,12 +1003,11 @@ static bool pum_adjust_info_position(win_T *wp, int width) wp->w_config.width = max_extra; wp->w_config.col = place_in_right ? col - 1 : pum_col - wp->w_config.width - 1; } - // when pum_above is SW otherwise is NW - wp->w_config.anchor = pum_above ? kFloatAnchorSouth : 0; + wp->w_config.anchor = 0; // NW: align top of info window with top of pum linenr_T count = wp->w_buffer->b_ml.ml_line_count; wp->w_view_width = wp->w_config.width; wp->w_config.height = plines_m_win(wp, wp->w_topline, count, Rows); - wp->w_config.row = pum_above ? pum_row + wp->w_config.height : pum_row; + wp->w_config.row = pum_row; wp->w_config.hide = false; win_config_float(wp, wp->w_config); return true; diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 631bc01d3a..3b7dcf3114 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1744,6 +1744,7 @@ describe('builtin popupmenu', function() exec([[ let g:list = [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "looooooooooooooong"}] let g:bufnrs = [] + let g:reduce_info_height = 0 funct Omni_test(findstart, base) if a:findstart return col(".") - 1 @@ -1763,11 +1764,15 @@ describe('builtin popupmenu', function() endfunc funct TsHl() let comp_info = complete_info(['selected']) - if get(comp_info, 'preview_bufnr', 0) > 0 - call v:lua.vim.treesitter.start(comp_info['preview_bufnr'], 'markdown') - endif if comp_info['selected'] == 0 - call nvim__complete_set(comp_info['selected'], {"info": "```lua\nfunction test()\n print('foo')\nend\n```"}) + let windata = nvim__complete_set(comp_info['selected'], {"info": "```lua\nfunction test()\n print('foo')\nend\n```"}) + call v:lua.vim.treesitter.start(windata['bufnr'], 'markdown') + if g:reduce_info_height > 0 + let h = v:lua.vim.api.nvim_win_text_height(windata['winid'], {}).all + if h > 3 + call v:lua.vim.api.nvim_win_set_height(windata['winid'], h - 3) + endif + endif endif endfunc augroup Group @@ -2154,7 +2159,48 @@ describe('builtin popupmenu', function() {5:-- }{6:match 1 of 3} | ]]) end - feed('') + end) + + it('info window aligns with pum when above cursor', function() + command('let g:reduce_info_height=1 | call TestTs()') + feed('18oi') + if multigrid then + screen:expect({ + grid = [[ + ## grid 1 + [2:----------------------------------------]|*10 + [3:----------------------------------------]| + ## grid 2 + |*9 + one^ | + ## grid 3 + {5:-- }{6:match 1 of 3} | + ## grid 4 + {mn:```}{102:lua}{n: }| + {102:function}{mn: }{103:test}{104:()}| + ## grid 5 + {12:one }| + {n:two }| + {n:looooooooooooooong }| + ]], + win_pos = { + [2] = { height = 10, startcol = 0, startrow = 0, width = 40, win = 1000 }, + }, + float_pos = { + [5] = { -1, 'SW', 2, 9, 0, false, 100, 2, 6, 0 }, + [4] = { 1001, 'NW', 1, 6, 19, false, 50, 1, 6, 19 }, + }, + }) + else + screen:expect([[ + |*6 + {12:one }{mn:```}{102:lua}{n: } | + {n:two }{102:function}{mn: }{103:test}{104:()} | + {n:looooooooooooooong } | + one^ | + {5:-- }{6:match 1 of 3} | + ]]) + end end) it('avoid modified original info text', function()