Skip to content

Add 'pumopt' option for popup menu transparency#19739

Open
mattn wants to merge 16 commits intovim:masterfrom
mattn:add-pumopacity
Open

Add 'pumopt' option for popup menu transparency#19739
mattn wants to merge 16 commits intovim:masterfrom
mattn:add-pumopacity

Conversation

@mattn
Copy link
Copy Markdown
Member

@mattn mattn commented Mar 18, 2026

Add the 'pumopacity' option (0-100, default 100) to control popup completion menu transparency, similar to the existing 'opacity' property for popup windows.

When pumopacity < 100, the background content shows through the popup menu. The implementation saves the background screen content before drawing the pum, then blends pum colors with the saved background using hl_pum_blend_attr() for space cells and hl_blend_attr() for text cells.

image

@h-east
Copy link
Copy Markdown
Member

h-east commented Mar 18, 2026

The options for pum (popup menu) have increased quite a bit ('pumborder', 'pumheight', 'pummaxwidth', 'pumwidth'). With 'pumopacity', that makes five.

It might be time to consider introducing a new 'pumopt' option to consolidate these, similar to 'diffopt', 'completeopt', and 'statuslineopt', ...

(Add:)
Example:

set pumopt=border:single,height:20,width:30,maxwidth:0,opacity:50
set pumopt+=border:custom:X;X;X;X;X;X;X;X

@chrisbra
Copy link
Copy Markdown
Member

Thanks, I tend to agree on a consolidated pumopt setting.

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 19, 2026

Should we treat 'pumborder', 'pumheight', 'pummaxwidth', and 'pumwidth' as ​​deprecated?

@h-east
Copy link
Copy Markdown
Member

h-east commented Mar 19, 2026

Yes, I think we should mark it as "deprecated" in the documentation and remove it in the next or the one after that major release.

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 20, 2026

I'm currently implementing pumopt. Please note that the addition of this option will change how pumwidth, pumheight, etc. have been handled.

When only width is specified in pumopt, height (i.e., pumheight) will be reset to its default value. In other words, to specify both pumwidth and pumheight using pumopt, you need to specify both at once:

set pumopt=width:20,height:10

I looked into the history of diffopt, statuslineopt, and completeopt, and found that all of them were introduced as single consolidated options from the start — none of them were introduced to consolidate pre-existing individual options like we are doing now.

So I plan to add a new error like e_option_is_deprecated and change pumwidth, pumheight, pumborder, pummaxwidth, and pumopacity to read-only. The values can still be read (e.g., echo &pumheight), but setting them will produce an error directing users to use pumopt instead.

image

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 20, 2026

I perfer to add new error e_option_is_deprecated . Anyone thought?

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 20, 2026

Anyway I should not include the error e_option_is_deprecated in this pull-request. Should be separated.

@h-east
Copy link
Copy Markdown
Member

h-east commented Mar 20, 2026

I'm currently out and haven't checked the existing source codes and documentation, but wouldn't the current behavior, where pumwidth and pumheight are interacting with each other, be considered a bug? Conversely, I don't understand the reason for doing so.

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 20, 2026

I looked into how other comma-separated string options behave when only some values are specified:

  • diffopt: set diffopt=icase resets all flags/context/algorithm to hardcoded defaults first, then only applies icase. filler, internal, etc. are all cleared.
  • completeopt: set completeopt=menu starts with new_flags = 0 and only sets the specified flags. All other flags are cleared.
  • statuslineopt: set statuslineopt=fixedheight initializes fixedheight=FALSE, maxheight=1 (defaults) first, then applies specified keys.
  • renderoptions: If type:directx is omitted, DirectX is disabled entirely.

All of these options reset unspecified values to their defaults. This is the standard behavior for comma-separated options in Vim. So set pumopt=width:3 resetting height to its default (0) is consistent with this pattern, not a bug.

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 20, 2026

As an aside, Vim currently has some precedent for deprecated options:

  • completefuzzycollect — marked as DEPRECATED in the docs. Setting it still succeeds, but cfc_flags is not referenced anywhere, so it has no effect at all.
  • wincolor — marked as DEPRECATED in the docs. Setting it internally redirects to winhighlight via update_wincolor(), so it still works but is redundant.

Neither of these produce an error when set. In a separate PR, I plan to introduce e_option_is_deprecated and make setting these (and the old pum options) produce an error, so that deprecated options are handled consistently.

@h-east
Copy link
Copy Markdown
Member

h-east commented Mar 20, 2026

I'm sorry, I completely misunderstood.
(I mistakenly thought you were saying that setting pumwidth clears the value of pumheight.)

When only width is specified in pumopt, height (i.e., pumheight) will be reset to its default value. In other words, to specify both pumwidth and pumheight using pumopt, you need to specify both at once:

set pumopt=width:20,height:10

Regarding the above, yes, that's how it's designed.
If you want to set it individually, you would use +=.

set pumopt+=width:3


(Added:)
I thought users might be surprised when the (legacy) option suddenly becomes an error the moment this PR is merged.
(Well, even if a grace period is provided, users will still be surprised the moment the grace period ends, haha.)

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 20, 2026

To clarify: this PR adds pumopacity and pumopt, but does not deprecate the existing individual options (pumwidth, pumheight, pumborder, pummaxwidth). They continue to work as before. The deprecation with e_option_is_deprecated will be handled in a separate PR.

#19768

@mattn mattn changed the title Add 'pumopacity' option for popup menu transparency Add 'pumopt' option for popup menu transparency Mar 21, 2026
@h-east
Copy link
Copy Markdown
Member

h-east commented Mar 22, 2026

Looking back at it, it doesn't make sense to add pumopacity when we decided to add pumopt.

@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 23, 2026

Removed pumopacity

mattn added 13 commits March 25, 2026 12:43
Add a new 'pumopacity' option (0-100) that controls the transparency
of the popup completion menu (pum).  When set, the underlying buffer
content shows through the pum's padding areas with blended attributes.

- pumopacity=0: fully opaque (default, normal pum behavior)
- pumopacity=1-99: partially transparent, higher = more transparent
- pumopacity=100: same as 0 (fully opaque)

Implementation saves the background screen content on the first pum
display and restores it for padding/space cells using hl_blend_attr()
for color blending.  Text cells are drawn normally with pum highlight.
Works with both cterm and termguicolors/GUI.
Move pum opacity blending from post-processing (pum_opacity_fill) into
screen_puts_len() and screen_fill() using the screen_pum_blend global.
This avoids double-blending issues and ensures text and space cells
use consistent blend calculations.

- screen_puts_len: blend text background with underlying attr
- screen_fill: restore underlying character and blend attrs
- pum_bg_* variables moved to globals.h for access from screen.c
- screen_pum_blend set during pum_redraw, cleared after
Add hl_pum_blend_attr() in highlight.c that blends fg and bg in the
correct direction for pum opacity:
- fg: pum_bg toward underlying_fg (opaque = text hidden, transparent = visible)
- bg: pum_bg toward underlying_bg (opaque = pum color, transparent = underlying)

This is different from hl_blend_attr(blend_fg=TRUE) which blends fg
in the opposite direction (designed for popup-over-popup compositing).

Use hl_pum_blend_attr() in screen_fill for pum space cells.
Use UPD_CLEAR in did_set_pumopacity to reset stale blended ScreenAttrs.
- Remove unused pum_opacity_fill() function and forward declaration
- Remove unused pum_opacity_active variable
- Remove duplicate if (over_cell > 0) condition
- Remove unnecessary comment
Add option value test (default, clamping, reset) and screendump tests
for pumopacity=50 and pumopacity=100.
Move next_col label outside of #ifdef FEAT_PROP_POPUP since it is also
used by the pum opacity code path.
The blend parameter is only used inside FEAT_GUI and FEAT_TERMGUICOLORS
blocks, so it triggers -Wunused-parameter when both are disabled.
Match the function declaration order to the implementation order in
popupmenu.c.
Invalidate cached background when screen size changes so the
blended pum background is re-captured from the updated screen.
Move 'pumopacity' after 'pummaxwidth' to maintain alphabetical order.
This fixes the Test_set_all_one_column test failure.
Add 'pumopt' as a single string option that controls popup menu
properties: border, height, width, maxwidth, opacity, shadow, margin.
This provides a consolidated alternative to the individual options
'pumborder', 'pumheight', 'pumwidth', 'pummaxwidth', and 'pumopacity'.

The existing individual options continue to work. Deprecation will be
handled in a separate change.

Example usage:
  :set pumopt=border:single,height:10,width:20,opacity:80

- Extract parse_pumopt_border() as shared border parser
- Add pum_opacity_changed() as public function
- Add expand_set_pumopt() for cmdline completion
- Update syntax/vim.vim, options.txt, gen_opt_test.vim
The standalone 'pumopacity' option is unnecessary since 'pumopt' already
supports opacity via the opacity:{n} key.  Remove the option definition
and move the internal p_po variable to globals.h.  Update tests to use
'pumopt=opacity:50' instead of 'set pumopacity=50'.
@mattn
Copy link
Copy Markdown
Member Author

mattn commented Mar 26, 2026

I found a behavior difference between pumheight and pumopt height:. The pum position differs — with pumopt=height:N the pum appears 2 lines lower than with set pumheight=N. Let me investigate and fix this before merging.

pumborder had reset to 0.

mattn added 2 commits March 26, 2026 18:08
pum_set_border_chars() unconditionally sets pum_border = 1.
Calling it with all zeros during pumopt reset re-enabled the border
right after PUM_BORDER_CLEAR() disabled it, causing the pum to appear
one row lower than expected.
- Draw border/shadow before setting screen_pum_blend so they render
  opaque instead of partially transparent.
- Expand pum_under_menu() to cover border, margin, and shadow areas
  to prevent flicker during completion selection.
- Remove text cell blending in screen_puts_len() that caused
  underlying syntax highlight colors to leak into pum foreground.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants