From: Hirohito Higashi Date: Sat, 18 Jul 2026 14:10:41 +0000 (+0000) Subject: patch 9.2.0795: popup menu shadow is not cleared when the menu shrinks X-Git-Tag: v9.2.0795^0 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6b9af206227eac03bfaf7b3b19774a14c145efa2;p=thirdparty%2Fvim.git patch 9.2.0795: popup menu shadow is not cleared when the menu shrinks Problem: When the popup menu shrinks its shadow is not cleared: a stale shadow cell is left on the empty (~) lines near the menu, and when the menu also gets narrower the border and text of the larger menu show through the shadow (Maxim Kim) Solution: Exclude the shadow corner cells that are never drawn, and when the menu is redrawn redraw the background under the shadow first, so content left by a larger menu is cleared instead of showing through (Hirohito Higashi). fixes: #20740 closes: #20750 Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Hirohito Higashi Signed-off-by: Christian Brabandt --- diff --git a/src/popupmenu.c b/src/popupmenu.c index 08aa442865..36000d9bf0 100644 --- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -425,12 +425,40 @@ pum_under_menu(int row, int col, int only_redrawing) + (pum_shadow ? 2 : 0); int extra_above = pum_border; int extra_below = pum_border + (pum_shadow ? 1 : 0); + int top = pum_row - extra_above; + int bot = pum_row + pum_height + extra_below; + int left = pum_col - 1 - extra_left; + int right = pum_col + pum_width + pum_scrollbar + extra_right; - return (!only_redrawing || pum_will_redraw) - && row >= pum_row - extra_above - && row < pum_row + pum_height + extra_below - && col >= pum_col - 1 - extra_left - && col < pum_col + pum_width + pum_scrollbar + extra_right; + if (!((!only_redrawing || pum_will_redraw) + && row >= top && row < bot && col >= left && col < right)) + return FALSE; + + if (pum_shadow) + { + // The shadow recolors the cells underneath. When the menu will be + // redrawn, leave the shadow cells unprotected so the window refreshes + // them first, clearing stale content left by a larger menu. + if (only_redrawing) + { + if (col >= right - 2 || row == bot - 1) + return FALSE; + } + else + { + // Menu stays as-is: exclude only the corner cells the shadow never + // draws. + int right_margin, left_margin, left_padding; + + compute_margins(&right_margin, &left_margin, &left_padding); + if (row == top && col >= right - 2) + return FALSE; + if (row == bot - 1 && col < pum_col + 2 - left_padding - pum_border + - left_margin) + return FALSE; + } + } + return TRUE; } /* diff --git a/src/testdir/dumps/Test_wildmenu_pum_shadow_1.dump b/src/testdir/dumps/Test_wildmenu_pum_shadow_1.dump new file mode 100644 index 0000000000..fe19d510b8 --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_shadow_1.dump @@ -0,0 +1,12 @@ +| +0#0000001#a8a8a8255@39 +|~+0#4040ff13&| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @4| +0#0000001#ffd7ff255|a|x@8| @4| +0#4040ff13#a8a8a8255@17 +|~| @4| +0#0000001#ffd7ff255|a|b| @12| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@15 +|~| @4| +0#0000001#ffd7ff255|a|c| @12| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@15 +|~| @6| +0#ffffff16#e000002@15| +0#4040ff13#a8a8a8255@15 +|:+0#0000001&|M|y|C|m|d| |a> @31 diff --git a/src/testdir/dumps/Test_wildmenu_pum_shadow_2.dump b/src/testdir/dumps/Test_wildmenu_pum_shadow_2.dump new file mode 100644 index 0000000000..d7370a954c --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_shadow_2.dump @@ -0,0 +1,12 @@ +| +0#0000001#a8a8a8255@39 +|~+0#4040ff13&| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @4| +0#0000001#ffd7ff255|a|b| @12| +0#4040ff13#a8a8a8255@17 +|~| @6| +0#ffffff16#e000002@15| +0#4040ff13#a8a8a8255@15 +|:+0#0000001&|M|y|C|m|d| |a|b> @30 diff --git a/src/testdir/dumps/Test_wildmenu_pum_shadow_border_1.dump b/src/testdir/dumps/Test_wildmenu_pum_shadow_border_1.dump new file mode 100644 index 0000000000..49316c7269 --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_shadow_border_1.dump @@ -0,0 +1,12 @@ +| +0#0000001#a8a8a8255@39 +|~+0#4040ff13&| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @3|┌+0#0000001#ffd7ff255|─@18|┐| +0#4040ff13#a8a8a8255@13 +|~| @3|│+0#0000001#ffd7ff255| |a|V|e|r|y|L|o|n|g|I|t|e|m|N|a|m|e| |│| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@11 +|~| @3|│+0#0000001#ffd7ff255| |a|b| @15|│| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@11 +|~| @3|│+0#0000001#ffd7ff255| |a|c| @15|│| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@11 +|~| @3|└+0#0000001#ffd7ff255|─@18|┘| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@11 +|~| @5| +0#ffffff16#e000002@20| +0#4040ff13#a8a8a8255@11 +|:+0#0000001&|M|y|C|m|d| |a> @31 diff --git a/src/testdir/dumps/Test_wildmenu_pum_shadow_border_2.dump b/src/testdir/dumps/Test_wildmenu_pum_shadow_border_2.dump new file mode 100644 index 0000000000..8b9d745312 --- /dev/null +++ b/src/testdir/dumps/Test_wildmenu_pum_shadow_border_2.dump @@ -0,0 +1,12 @@ +| +0#0000001#a8a8a8255@39 +|~+0#4040ff13&| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @38 +|~| @3|┌+0#0000001#ffd7ff255|─@15|┐| +0#4040ff13#a8a8a8255@16 +|~| @3|│+0#0000001#ffd7ff255| |a|b| @12|│| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@14 +|~| @3|└+0#0000001#ffd7ff255|─@15|┘| +0#ffffff16#e000002@1| +0#4040ff13#a8a8a8255@14 +|~| @5| +0#ffffff16#e000002@17| +0#4040ff13#a8a8a8255@14 +|:+0#0000001&|M|y|C|m|d| |a|b> @30 diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index ef1cd7adcd..ef036d2b03 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -226,6 +226,85 @@ func Test_wildmenu_screendump() call StopVimInTerminal(buf) endfunc +" When the wildmenu popup menu shrinks, its shadow must be cleared, also on the +" empty (~) lines above the menu. See issue #20740. +func Test_wildmenu_pum_shadow() + CheckScreendump + + let lines =<< trim [SCRIPT] + func MyCompl(a, l, p) + return filter(['axxxxxxxxx', 'ab', 'ac'], 'stridx(v:val, a:a) == 0') + endfunc + command! -nargs=1 -complete=customlist,MyCompl MyCmd echo + set wildmode=noselect:lastused,full + set wildoptions=pum,fuzzy + set pumopt=shadow + set shortmess+=I + " Give the shadow a distinct color so it is easy to tell apart from the + " background in the screen dump. + hi Normal ctermbg=grey ctermfg=black guibg=grey guifg=black + hi PmenuShadow ctermbg=darkred ctermfg=white guibg=darkred guifg=white + autocmd CmdlineChanged : call wildtrigger() + [SCRIPT] + call writefile(lines, 'XTest_wildshadow', 'D') + + let buf = RunVimInTerminal('-S XTest_wildshadow', {'rows': 12, 'cols': 40}) + + " Wide popup with a shadow drawn over the ~ lines. + call term_sendkeys(buf, ":MyCmd a") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_shadow_1', {}) + + " Narrow the matches: the popup shrinks and the wider shadow must be cleared. + call term_sendkeys(buf, "b") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_shadow_2', {}) + + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) +endfunc + +" Same as above but with a border, and the menu also gets narrower. When the +" menu shrinks the stale content of the wider menu must be cleared before the +" shadow is drawn over it, otherwise the old border and text show through the +" shadow. See issue #20740. +func Test_wildmenu_pum_shadow_border() + CheckScreendump + + let lines =<< trim [SCRIPT] + func MyCompl(a, l, p) + return filter(['aVeryLongItemName', 'ab', 'ac'], 'stridx(v:val, a:a) == 0') + endfunc + command! -nargs=1 -complete=customlist,MyCompl MyCmd echo + set wildmode=noselect:lastused,full + set wildoptions=pum,fuzzy + set pumopt=shadow,border:single + set shortmess+=I + " Give the shadow a distinct color so it is easy to tell apart from the + " background in the screen dump. + hi Normal ctermbg=grey ctermfg=black guibg=grey guifg=black + hi PmenuShadow ctermbg=darkred ctermfg=white guibg=darkred guifg=white + autocmd CmdlineChanged : call wildtrigger() + [SCRIPT] + call writefile(lines, 'XTest_wildshadowborder', 'D') + + let buf = RunVimInTerminal('-S XTest_wildshadowborder', {'rows': 12, 'cols': 40}) + + " Wide popup with a border and a shadow drawn over the ~ lines. + call term_sendkeys(buf, ":MyCmd a") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_shadow_border_1', {}) + + " Narrow the matches: the popup shrinks in both width and height, the wider + " menu's border and text must be cleared next to and under the shadow. + call term_sendkeys(buf, "b") + call TermWait(buf, 50) + call VerifyScreenDump(buf, 'Test_wildmenu_pum_shadow_border_2', {}) + + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) +endfunc + func Test_wildmenu_with_input_func() CheckScreendump diff --git a/src/version.c b/src/version.c index d2d3c45dcc..e0861aa389 100644 --- a/src/version.c +++ b/src/version.c @@ -759,6 +759,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 795, /**/ 794, /**/