]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0795: popup menu shadow is not cleared when the menu shrinks v9.2.0795
authorHirohito Higashi <h.east.727@gmail.com>
Sat, 18 Jul 2026 14:10:41 +0000 (14:10 +0000)
committerChristian Brabandt <cb@256bit.org>
Sat, 18 Jul 2026 14:10:41 +0000 (14:10 +0000)
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) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/popupmenu.c
src/testdir/dumps/Test_wildmenu_pum_shadow_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_wildmenu_pum_shadow_2.dump [new file with mode: 0644]
src/testdir/dumps/Test_wildmenu_pum_shadow_border_1.dump [new file with mode: 0644]
src/testdir/dumps/Test_wildmenu_pum_shadow_border_2.dump [new file with mode: 0644]
src/testdir/test_cmdline.vim
src/version.c

index 08aa442865f04e4cae444b529b2bc702a1ea8e03..36000d9bf013175686ec843bfa4955a3eccf58ac 100644 (file)
@@ -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 (file)
index 0000000..fe19d51
--- /dev/null
@@ -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 (file)
index 0000000..d7370a9
--- /dev/null
@@ -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 (file)
index 0000000..49316c7
--- /dev/null
@@ -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 (file)
index 0000000..8b9d745
--- /dev/null
@@ -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
index ef1cd7adcd93dabc02a8ac12114e5b65ecc18f5b..ef036d2b0376c221641b0976f989533cf176f67d 100644 (file)
@@ -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 <q-args>
+    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, "\<Esc>")
+  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 <q-args>
+    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, "\<Esc>")
+  call StopVimInTerminal(buf)
+endfunc
+
 func Test_wildmenu_with_input_func()
   CheckScreendump
 
index d2d3c45dcca2f35203a66d2bcd68808dc7abea1e..e0861aa389d15076f72b2463d0563e7c3d6af3eb 100644 (file)
@@ -759,6 +759,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    795,
 /**/
     794,
 /**/