mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
patch 9.2.0318: cannot configure opacity for popup menu
Problem: cannot configure opacity for popup menu
Solution: Add the 'pumopt' option, consolidate existing pum options into
the pumopt option (Yasuhiro Matsumoto)
closes: #19931
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
f3cba4a205
commit
317351c745
@@ -125,6 +125,23 @@ EXTERN int screen_zindex INIT(= 0);
|
||||
EXTERN win_T *screen_opacity_popup INIT(= NULL);
|
||||
#endif
|
||||
|
||||
// Pum opacity level (0 = fully transparent, 100 = fully opaque).
|
||||
// Set via 'pumopt' opacity: key.
|
||||
EXTERN long p_po INIT(= 100);
|
||||
|
||||
// Blend value for popup menu opacity (0 = off, 1-99 = blend level).
|
||||
// Set during pum drawing when pum opacity is active.
|
||||
EXTERN int screen_pum_blend INIT(= 0);
|
||||
|
||||
// Saved background screen content for pum opacity blending.
|
||||
EXTERN sattr_T *pum_bg_attrs INIT(= NULL);
|
||||
EXTERN schar_T *pum_bg_lines INIT(= NULL);
|
||||
EXTERN u8char_T *pum_bg_linesUC INIT(= NULL);
|
||||
EXTERN u8char_T *pum_bg_linesC[MAX_MCO];
|
||||
EXTERN int pum_bg_top INIT(= 0);
|
||||
EXTERN int pum_bg_bot INIT(= 0);
|
||||
EXTERN int pum_bg_cols INIT(= 0);
|
||||
|
||||
EXTERN int screen_Rows INIT(= 0); // actual size of ScreenLines[]
|
||||
EXTERN int screen_Columns INIT(= 0); // actual size of ScreenLines[]
|
||||
|
||||
|
||||
+132
@@ -3321,6 +3321,138 @@ hl_blend_attr(int char_attr, int popup_attr, int blend, int blend_fg UNUSED)
|
||||
return get_attr_entry(&term_attr_table, &new_en);
|
||||
}
|
||||
|
||||
/*
|
||||
* Blend for pum opacity space cells: keep underlying fg, blend bg.
|
||||
* This is different from hl_blend_attr(blend_fg=TRUE) where fg blends
|
||||
* in the wrong direction for pum use.
|
||||
*/
|
||||
int
|
||||
hl_pum_blend_attr(int char_attr, int popup_attr, int blend UNUSED)
|
||||
{
|
||||
attrentry_T *char_aep = NULL;
|
||||
attrentry_T *popup_aep;
|
||||
attrentry_T new_en;
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
if (gui.in_use)
|
||||
{
|
||||
if (char_attr > HL_ALL)
|
||||
char_aep = syn_gui_attr2entry(char_attr);
|
||||
if (char_aep != NULL)
|
||||
new_en = *char_aep;
|
||||
else
|
||||
{
|
||||
CLEAR_FIELD(new_en);
|
||||
new_en.ae_u.gui.fg_color = INVALCOLOR;
|
||||
new_en.ae_u.gui.bg_color = INVALCOLOR;
|
||||
new_en.ae_u.gui.sp_color = INVALCOLOR;
|
||||
if (char_attr <= HL_ALL)
|
||||
new_en.ae_attr = char_attr;
|
||||
}
|
||||
if (popup_attr > HL_ALL)
|
||||
{
|
||||
popup_aep = syn_gui_attr2entry(popup_attr);
|
||||
if (popup_aep != NULL)
|
||||
{
|
||||
// Blend fg: pum_bg toward underlying_fg.
|
||||
// blend=0 (opaque): fg = pum_bg (text hidden)
|
||||
// blend=100 (transparent): fg = underlying_fg (text visible)
|
||||
if (popup_aep->ae_u.gui.bg_color != INVALCOLOR)
|
||||
{
|
||||
int base_fg = 0xFFFFFF;
|
||||
if (char_aep != NULL
|
||||
&& char_aep->ae_u.gui.fg_color != INVALCOLOR)
|
||||
base_fg = char_aep->ae_u.gui.fg_color;
|
||||
new_en.ae_u.gui.fg_color = blend_colors(
|
||||
popup_aep->ae_u.gui.bg_color, base_fg, blend);
|
||||
}
|
||||
// Blend bg: popup bg toward underlying bg.
|
||||
if (popup_aep->ae_u.gui.bg_color != INVALCOLOR)
|
||||
{
|
||||
guicolor_T underlying_bg = INVALCOLOR;
|
||||
if (char_aep != NULL)
|
||||
underlying_bg = char_aep->ae_u.gui.bg_color;
|
||||
new_en.ae_u.gui.bg_color = blend_colors(
|
||||
popup_aep->ae_u.gui.bg_color,
|
||||
underlying_bg, blend);
|
||||
}
|
||||
}
|
||||
}
|
||||
return get_attr_entry(&gui_attr_table, &new_en);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IS_CTERM)
|
||||
{
|
||||
if (char_attr > HL_ALL)
|
||||
char_aep = syn_cterm_attr2entry(char_attr);
|
||||
if (char_aep != NULL)
|
||||
new_en = *char_aep;
|
||||
else
|
||||
{
|
||||
CLEAR_FIELD(new_en);
|
||||
#ifdef FEAT_TERMGUICOLORS
|
||||
new_en.ae_u.cterm.bg_rgb = INVALCOLOR;
|
||||
new_en.ae_u.cterm.fg_rgb = INVALCOLOR;
|
||||
new_en.ae_u.cterm.ul_rgb = INVALCOLOR;
|
||||
#endif
|
||||
if (char_attr <= HL_ALL)
|
||||
new_en.ae_attr = char_attr;
|
||||
}
|
||||
if (popup_attr > HL_ALL)
|
||||
{
|
||||
popup_aep = syn_cterm_attr2entry(popup_attr);
|
||||
if (popup_aep != NULL)
|
||||
{
|
||||
// Blend cterm fg: use popup bg (hides text when opaque)
|
||||
if (popup_aep->ae_u.cterm.fg_color > 0)
|
||||
new_en.ae_u.cterm.fg_color =
|
||||
popup_aep->ae_u.cterm.fg_color;
|
||||
// Use popup cterm bg.
|
||||
if (popup_aep->ae_u.cterm.bg_color > 0)
|
||||
new_en.ae_u.cterm.bg_color =
|
||||
popup_aep->ae_u.cterm.bg_color;
|
||||
#ifdef FEAT_TERMGUICOLORS
|
||||
// Blend fg_rgb: pum_bg toward underlying_fg.
|
||||
if (popup_aep->ae_u.cterm.bg_rgb != INVALCOLOR)
|
||||
{
|
||||
int base_fg = 0xFFFFFF;
|
||||
if (char_aep != NULL
|
||||
&& char_aep->ae_u.cterm.fg_rgb != INVALCOLOR)
|
||||
base_fg = char_aep->ae_u.cterm.fg_rgb;
|
||||
new_en.ae_u.cterm.fg_rgb = blend_colors(
|
||||
popup_aep->ae_u.cterm.bg_rgb, base_fg, blend);
|
||||
}
|
||||
// Blend bg_rgb.
|
||||
if (popup_aep->ae_u.cterm.bg_rgb != INVALCOLOR)
|
||||
{
|
||||
guicolor_T underlying_bg = INVALCOLOR;
|
||||
if (char_aep != NULL)
|
||||
underlying_bg = char_aep->ae_u.cterm.bg_rgb;
|
||||
new_en.ae_u.cterm.bg_rgb = blend_colors(
|
||||
popup_aep->ae_u.cterm.bg_rgb,
|
||||
underlying_bg, blend);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return get_attr_entry(&cterm_attr_table, &new_en);
|
||||
}
|
||||
|
||||
// term mode
|
||||
if (char_attr > HL_ALL)
|
||||
char_aep = syn_term_attr2entry(char_attr);
|
||||
if (char_aep != NULL)
|
||||
new_en = *char_aep;
|
||||
else
|
||||
{
|
||||
CLEAR_FIELD(new_en);
|
||||
if (char_attr <= HL_ALL)
|
||||
new_en.ae_attr = char_attr;
|
||||
}
|
||||
return get_attr_entry(&term_attr_table, &new_en);
|
||||
}
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
attrentry_T *
|
||||
syn_gui_attr2entry(int attr)
|
||||
|
||||
@@ -556,6 +556,7 @@ EXTERN long p_ph; // 'pumheight'
|
||||
EXTERN long p_pw; // 'pumwidth'
|
||||
EXTERN long p_pmw; // 'pummaxwidth'
|
||||
EXTERN char_u *p_pb; // 'pumborder'
|
||||
EXTERN char_u *p_pumopt; // 'pumopt'
|
||||
EXTERN char_u *p_com; // 'comments'
|
||||
EXTERN char_u *p_cpo; // 'cpoptions'
|
||||
#ifdef FEAT_CSCOPE
|
||||
|
||||
@@ -2091,6 +2091,10 @@ static struct vimoption options[] =
|
||||
{"pummaxwidth", "pmw", P_NUM|P_VI_DEF,
|
||||
(char_u *)&p_pmw, PV_NONE, NULL, NULL,
|
||||
{(char_u *)0L, (char_u *)0L} SCTX_INIT},
|
||||
{"pumopt", NULL, P_STRING|P_VI_DEF|P_COMMA|P_NODUP|P_COLON,
|
||||
(char_u *)&p_pumopt, PV_NONE,
|
||||
did_set_pumopt, expand_set_pumopt,
|
||||
{(char_u *)"", (char_u *)NULL} SCTX_INIT},
|
||||
{"pumwidth", "pw", P_NUM|P_VI_DEF,
|
||||
(char_u *)&p_pw, PV_NONE, NULL, NULL,
|
||||
{(char_u *)15L, (char_u *)15L} SCTX_INIT},
|
||||
|
||||
+204
-69
@@ -3696,6 +3696,197 @@ expand_set_rightleftcmd(optexpand_T *args, int *numMatches, char_u ***matches)
|
||||
pum_set_margin(FALSE); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Parse a border value from a pumopt "border:" token.
|
||||
* Returns OK on success, FAIL on error.
|
||||
*/
|
||||
static int
|
||||
parse_pumopt_border(char_u *val, int len)
|
||||
{
|
||||
// Use box-drawing characters only when 'encoding' is "utf-8" and
|
||||
// 'ambiwidth' is "single".
|
||||
int can_use_box_chars = (enc_utf8 && *p_ambw == 's');
|
||||
char_u *token;
|
||||
|
||||
token = vim_strnsave(val, len);
|
||||
if (token == NULL)
|
||||
return FAIL;
|
||||
|
||||
if (can_use_box_chars && STRCMP(token, "single") == 0)
|
||||
pum_set_border_chars(0x2500, 0x2502, 0x2500, 0x2502, // ─ │ ─ │
|
||||
0x250c, 0x2510, 0x2518, 0x2514); // ┌ ┐ ┘ └
|
||||
else if (can_use_box_chars && STRCMP(token, "double") == 0)
|
||||
pum_set_border_chars(0x2550, 0x2551, 0x2550, 0x2551, // ═ ║ ═ ║
|
||||
0x2554, 0x2557, 0x255D, 0x255A); // ╔ ╗ ╝ ╚
|
||||
else if (can_use_box_chars && STRCMP(token, "round") == 0)
|
||||
pum_set_border_chars(0x2500, 0x2502, 0x2500, 0x2502, // ─ │ ─ │
|
||||
0x256d, 0x256e, 0x256f, 0x2570); // ╭ ╮ ╯ ╰
|
||||
else if (STRCMP(token, "ascii") == 0)
|
||||
pum_set_border_chars('-', '|', '-', '|', '+', '+', '+', '+');
|
||||
else if (STRNCMP(token, "custom:", 7) == 0)
|
||||
{
|
||||
char_u *q = token + 7;
|
||||
int out[8];
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (*q == NUL || *q == ',')
|
||||
{
|
||||
vim_free(token);
|
||||
return FAIL;
|
||||
}
|
||||
out[i] = mb_ptr2char(q);
|
||||
mb_ptr2char_adv(&q);
|
||||
if (i < 7)
|
||||
{
|
||||
if (*q != ';')
|
||||
{
|
||||
vim_free(token);
|
||||
return FAIL;
|
||||
}
|
||||
q++;
|
||||
}
|
||||
}
|
||||
if (*q != NUL && *q != ',')
|
||||
{
|
||||
vim_free(token);
|
||||
return FAIL;
|
||||
}
|
||||
pum_set_border_chars(out[0], out[1], out[2], out[3], out[4], out[5],
|
||||
out[6], out[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_free(token);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
vim_free(token);
|
||||
pum_set_border(TRUE);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'pumopt' option is changed.
|
||||
* Format: comma-separated key:value pairs.
|
||||
* border:{single|double|round|ascii|custom:X;X;X;X;X;X;X;X}
|
||||
* height:{n}
|
||||
* width:{n}
|
||||
* maxwidth:{n}
|
||||
* opacity:{n}
|
||||
* shadow
|
||||
* margin (requires border)
|
||||
*/
|
||||
char *
|
||||
did_set_pumopt(optset_T *args)
|
||||
{
|
||||
char_u **varp = (char_u **)args->os_varp;
|
||||
char_u *p;
|
||||
int have_border = FALSE;
|
||||
int have_margin = FALSE;
|
||||
|
||||
// Reset to defaults.
|
||||
PUM_BORDER_CLEAR();
|
||||
p_ph = 0;
|
||||
p_pw = 15;
|
||||
p_pmw = 0;
|
||||
p_po = 100;
|
||||
|
||||
if (*varp == NULL || **varp == NUL)
|
||||
return NULL;
|
||||
|
||||
for (p = *varp; p != NULL && *p != NUL; )
|
||||
{
|
||||
char_u *comma = vim_strchr(p, ',');
|
||||
int len;
|
||||
|
||||
if (comma != NULL)
|
||||
len = (int)(comma - p);
|
||||
else
|
||||
len = (int)STRLEN(p);
|
||||
|
||||
if (STRNCMP(p, "border:", 7) == 0)
|
||||
{
|
||||
if (have_border)
|
||||
goto error;
|
||||
have_border = TRUE;
|
||||
if (parse_pumopt_border(p + 7, len - 7) == FAIL)
|
||||
goto error;
|
||||
}
|
||||
else if (STRNCMP(p, "height:", 7) == 0)
|
||||
{
|
||||
long n = atol((char *)p + 7);
|
||||
if (n < 0)
|
||||
goto error;
|
||||
p_ph = n;
|
||||
}
|
||||
else if (STRNCMP(p, "width:", 6) == 0)
|
||||
{
|
||||
long n = atol((char *)p + 6);
|
||||
if (n < 0)
|
||||
goto error;
|
||||
p_pw = n;
|
||||
}
|
||||
else if (STRNCMP(p, "maxwidth:", 9) == 0)
|
||||
{
|
||||
long n = atol((char *)p + 9);
|
||||
if (n < 0)
|
||||
goto error;
|
||||
p_pmw = n;
|
||||
}
|
||||
else if (STRNCMP(p, "opacity:", 8) == 0)
|
||||
{
|
||||
long n = atol((char *)p + 8);
|
||||
if (n < 0 || n > 100)
|
||||
goto error;
|
||||
p_po = n;
|
||||
}
|
||||
else if (len == 6 && STRNCMP(p, "shadow", 6) == 0)
|
||||
pum_set_shadow(TRUE);
|
||||
else if (len == 6 && STRNCMP(p, "margin", 6) == 0)
|
||||
{
|
||||
have_margin = TRUE;
|
||||
pum_set_margin(TRUE);
|
||||
}
|
||||
else
|
||||
goto error;
|
||||
|
||||
if (comma != NULL)
|
||||
p = comma + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (have_margin && !have_border)
|
||||
goto error;
|
||||
|
||||
// Invalidate cached background for opacity changes.
|
||||
pum_opacity_changed();
|
||||
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
PUM_BORDER_CLEAR();
|
||||
p_ph = 0;
|
||||
p_pw = 15;
|
||||
p_pmw = 0;
|
||||
p_po = 100;
|
||||
return e_invalid_argument;
|
||||
}
|
||||
|
||||
int
|
||||
expand_set_pumopt(optexpand_T *args, int *numMatches, char_u ***matches)
|
||||
{
|
||||
static char *(p_pumopt_values[]) = {"border:", "height:", "width:",
|
||||
"maxwidth:", "opacity:", "shadow", "margin", NULL};
|
||||
return expand_set_opt_string(
|
||||
args,
|
||||
p_pumopt_values,
|
||||
ARRAY_LENGTH(p_pumopt_values) - 1,
|
||||
numMatches,
|
||||
matches);
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'pumborder' option is changed.
|
||||
* Rules:
|
||||
@@ -3707,10 +3898,7 @@ expand_set_rightleftcmd(optexpand_T *args, int *numMatches, char_u ***matches)
|
||||
did_set_pumborder(optset_T *args)
|
||||
{
|
||||
char_u **varp = (char_u **)args->os_varp;
|
||||
// Use box-drawing characters only when 'encoding' is "utf-8" and
|
||||
// 'ambiwidth' is "single".
|
||||
int can_use_box_chars = (enc_utf8 && *p_ambw == 's');
|
||||
char_u *p, *token;
|
||||
char_u *p;
|
||||
int len;
|
||||
int have_border = FALSE;
|
||||
int have_margin = FALSE;
|
||||
@@ -3722,89 +3910,36 @@ did_set_pumborder(optset_T *args)
|
||||
|
||||
for (p = *varp; p != NULL && *p != NUL; )
|
||||
{
|
||||
// end of token is either ',' or NUL
|
||||
char_u *comma = vim_strchr(p, ',');
|
||||
if (comma != NULL)
|
||||
len = (int)(comma - p);
|
||||
else
|
||||
len = (int)STRLEN(p);
|
||||
|
||||
token = vim_strnsave(p, len);
|
||||
if (token == NULL)
|
||||
goto error;
|
||||
|
||||
if ((can_use_box_chars && (STRCMP(token, "single") == 0
|
||||
|| STRCMP(token, "double") == 0
|
||||
|| STRCMP(token, "round") == 0))
|
||||
|| STRCMP(token, "ascii") == 0
|
||||
|| (STRNCMP(token, "custom:", 7) == 0))
|
||||
{
|
||||
if (have_border)
|
||||
{
|
||||
// multiple border styles not allowed
|
||||
vim_free(token);
|
||||
goto error;
|
||||
}
|
||||
have_border = TRUE;
|
||||
|
||||
if (STRCMP(token, "single") == 0)
|
||||
pum_set_border_chars(0x2500, 0x2502, 0x2500, 0x2502, // ─ │ ─ │
|
||||
0x250c, 0x2510, 0x2518, 0x2514); // ┌ ┐ ┘ └
|
||||
else if (STRCMP(token, "double") == 0)
|
||||
pum_set_border_chars(0x2550, 0x2551, 0x2550, 0x2551, // ═ ║ ═ ║
|
||||
0x2554, 0x2557, 0x255D, 0x255A); // ╔ ╗ ╝ ╚
|
||||
else if (STRCMP(token, "round") == 0)
|
||||
pum_set_border_chars(0x2500, 0x2502, 0x2500, 0x2502, // ─ │ ─ │
|
||||
0x256d, 0x256e, 0x256f, 0x2570); // ╭ ╮ ╯ ╰
|
||||
else if (STRCMP(token, "ascii") == 0)
|
||||
pum_set_border_chars('-', '|', '-', '|', '+', '+', '+', '+');
|
||||
else if (STRNCMP(token, "custom:", 7) == 0)
|
||||
{
|
||||
char_u *q = token + 7;
|
||||
int out[8];
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (*q == NUL || *q == ',')
|
||||
goto error;
|
||||
out[i] = mb_ptr2char(q);
|
||||
mb_ptr2char_adv(&q);
|
||||
if (i < 7)
|
||||
{
|
||||
if (*q != ';')
|
||||
goto error; // must be semicolon
|
||||
q++;
|
||||
}
|
||||
}
|
||||
if (*q != NUL && *q != ',') // must end exactly after the 8th char
|
||||
goto error;
|
||||
pum_set_border_chars(out[0], out[1], out[2], out[3], out[4], out[5],
|
||||
out[6], out[7]);
|
||||
}
|
||||
}
|
||||
else if (STRCMP(token, "shadow") == 0)
|
||||
if (STRNCMP(p, "shadow", len) == 0 && len == 6)
|
||||
pum_set_shadow(TRUE);
|
||||
else if (STRCMP(token, "margin") == 0)
|
||||
else if (STRNCMP(p, "margin", len) == 0 && len == 6)
|
||||
{
|
||||
have_margin = TRUE;
|
||||
pum_set_margin(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
vim_free(token);
|
||||
goto error;
|
||||
if (have_border)
|
||||
goto error;
|
||||
have_border = TRUE;
|
||||
if (parse_pumopt_border(p, len) == FAIL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
vim_free(token);
|
||||
|
||||
if (comma != NULL)
|
||||
p = comma + 1; // move to next token (skip comma)
|
||||
p = comma + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (have_margin && !have_border)
|
||||
goto error; // margin must be combined with border
|
||||
goto error;
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -3817,12 +3952,12 @@ error:
|
||||
int
|
||||
expand_set_pumborder(optexpand_T *args, int *numMatches, char_u ***matches)
|
||||
{
|
||||
static char *(p_rlc_values[]) = {"single", "double", "round", "ascii",
|
||||
static char *(p_pb_values[]) = {"single", "double", "round", "ascii",
|
||||
"custom", "shadow", "margin", NULL};
|
||||
return expand_set_opt_string(
|
||||
args,
|
||||
p_rlc_values,
|
||||
ARRAY_LENGTH(p_rlc_values) - 1,
|
||||
p_pb_values,
|
||||
ARRAY_LENGTH(p_pb_values) - 1,
|
||||
numMatches,
|
||||
matches);
|
||||
}
|
||||
|
||||
Generated
+4
-1
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Vim\n"
|
||||
"Report-Msgid-Bugs-To: vim-dev@vim.org\n"
|
||||
"POT-Creation-Date: 2026-04-07 18:24+0000\n"
|
||||
"POT-Creation-Date: 2026-04-07 19:50+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -10015,6 +10015,9 @@ msgstr ""
|
||||
msgid "popup border style"
|
||||
msgstr ""
|
||||
|
||||
msgid "additional options for the popup menu"
|
||||
msgstr ""
|
||||
|
||||
msgid "user defined function for Insert mode completion"
|
||||
msgstr ""
|
||||
|
||||
|
||||
+152
-13
@@ -406,11 +406,17 @@ pum_call_update_screen(void)
|
||||
int
|
||||
pum_under_menu(int row, int col, int only_redrawing)
|
||||
{
|
||||
int extra_left = pum_border + (pum_margin && pum_border ? 1 : 0);
|
||||
int extra_right = pum_border + (pum_margin && pum_border ? 1 : 0)
|
||||
+ (pum_shadow ? 2 : 0);
|
||||
int extra_above = pum_border;
|
||||
int extra_below = pum_border + (pum_shadow ? 1 : 0);
|
||||
|
||||
return (!only_redrawing || pum_will_redraw)
|
||||
&& row >= pum_row
|
||||
&& row < pum_row + pum_height
|
||||
&& col >= pum_col - 1
|
||||
&& col < pum_col + pum_width + pum_scrollbar;
|
||||
&& 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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -878,6 +884,42 @@ pum_align_order(int *order)
|
||||
order[2] = is_default ? CPT_MENU : cia_flags % 10;
|
||||
}
|
||||
|
||||
static void pum_free_bg(void);
|
||||
|
||||
/*
|
||||
* Called when the pum opacity value has changed.
|
||||
* Invalidates cached background and triggers redraw if pum is visible.
|
||||
*/
|
||||
void
|
||||
pum_opacity_changed(void)
|
||||
{
|
||||
// Invalidate cached background so it gets re-saved.
|
||||
pum_free_bg();
|
||||
|
||||
if (pum_visible())
|
||||
{
|
||||
// Force full screen clear so ScreenAttrs doesn't retain
|
||||
// stale blended values from the previous pumopacity.
|
||||
redraw_all_later(UPD_CLEAR);
|
||||
call_update_screen = TRUE;
|
||||
pum_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pum_free_bg(void)
|
||||
{
|
||||
int k;
|
||||
VIM_CLEAR(pum_bg_attrs);
|
||||
VIM_CLEAR(pum_bg_lines);
|
||||
VIM_CLEAR(pum_bg_linesUC);
|
||||
for (k = 0; k < MAX_MCO; ++k)
|
||||
VIM_CLEAR(pum_bg_linesC[k]);
|
||||
pum_bg_top = 0;
|
||||
pum_bg_bot = 0;
|
||||
pum_bg_cols = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Redraw the popup menu, using "pum_first" and "pum_selected".
|
||||
*/
|
||||
@@ -906,6 +948,7 @@ pum_redraw(void)
|
||||
int orig_attr = -1;
|
||||
int scroll_range = pum_size - pum_height;
|
||||
bool override_success;
|
||||
int opacity_active = (p_po > 0 && p_po < 100);
|
||||
|
||||
// Use current window for highlight overrides when using 'winhighlight'
|
||||
override_success = push_highlight_overrides(curwin->w_hl, curwin->w_hl_len);
|
||||
@@ -925,11 +968,97 @@ pum_redraw(void)
|
||||
if (call_update_screen)
|
||||
{
|
||||
call_update_screen = FALSE;
|
||||
// Do not redraw in pum_may_redraw() and don't draw in the area where
|
||||
// the popup menu will be.
|
||||
pum_will_redraw = TRUE;
|
||||
update_screen(0);
|
||||
pum_will_redraw = FALSE;
|
||||
// Invalidate cached background if screen size changed (e.g.
|
||||
// after window resize).
|
||||
if (opacity_active && pum_bg_lines != NULL
|
||||
&& (pum_bg_cols != screen_Columns
|
||||
|| pum_bg_bot > screen_Rows))
|
||||
pum_free_bg();
|
||||
|
||||
if (opacity_active && pum_bg_lines != NULL)
|
||||
{
|
||||
// Already have saved background; skip update_screen to avoid
|
||||
// flickering. Just do a normal pum_will_redraw update.
|
||||
pum_will_redraw = TRUE;
|
||||
update_screen(0);
|
||||
pum_will_redraw = FALSE;
|
||||
}
|
||||
else if (opacity_active)
|
||||
{
|
||||
// For opacity: draw background including the area under the
|
||||
// pum, then save it.
|
||||
pum_pretend_not_visible = TRUE;
|
||||
update_screen(0);
|
||||
pum_pretend_not_visible = FALSE;
|
||||
|
||||
// Save background to static buffers.
|
||||
if (ScreenLines != NULL && ScreenAttrs != NULL)
|
||||
{
|
||||
int save_top, save_bot, save_ncells, k;
|
||||
|
||||
pum_free_bg();
|
||||
save_top = pum_row - pum_border;
|
||||
save_bot = pum_row + pum_height + pum_border
|
||||
+ (pum_shadow ? 1 : 0) + 1;
|
||||
if (save_top < 0)
|
||||
save_top = 0;
|
||||
if (save_bot > screen_Rows)
|
||||
save_bot = screen_Rows;
|
||||
pum_bg_top = save_top;
|
||||
pum_bg_bot = save_bot;
|
||||
pum_bg_cols = screen_Columns;
|
||||
if (save_top < save_bot)
|
||||
{
|
||||
save_ncells = (save_bot - save_top) * screen_Columns;
|
||||
pum_bg_attrs = LALLOC_MULT(sattr_T, save_ncells);
|
||||
pum_bg_lines = LALLOC_MULT(schar_T, save_ncells);
|
||||
if (enc_utf8)
|
||||
{
|
||||
pum_bg_linesUC = LALLOC_MULT(u8char_T, save_ncells);
|
||||
for (k = 0; k < MAX_MCO; ++k)
|
||||
pum_bg_linesC[k] = LALLOC_MULT(u8char_T,
|
||||
save_ncells);
|
||||
}
|
||||
if (pum_bg_attrs != NULL && pum_bg_lines != NULL)
|
||||
{
|
||||
for (int r = save_top; r < save_bot; ++r)
|
||||
{
|
||||
int soff = (r - save_top) * screen_Columns;
|
||||
int loff = LineOffset[r];
|
||||
|
||||
mch_memmove(pum_bg_attrs + soff,
|
||||
ScreenAttrs + loff,
|
||||
screen_Columns * sizeof(sattr_T));
|
||||
mch_memmove(pum_bg_lines + soff,
|
||||
ScreenLines + loff,
|
||||
screen_Columns * sizeof(schar_T));
|
||||
if (enc_utf8 && pum_bg_linesUC != NULL
|
||||
&& ScreenLinesUC != NULL)
|
||||
{
|
||||
mch_memmove(pum_bg_linesUC + soff,
|
||||
ScreenLinesUC + loff,
|
||||
screen_Columns * sizeof(u8char_T));
|
||||
for (k = 0; k < MAX_MCO; ++k)
|
||||
if (pum_bg_linesC[k] != NULL
|
||||
&& ScreenLinesC[k] != NULL)
|
||||
mch_memmove(pum_bg_linesC[k] + soff,
|
||||
ScreenLinesC[k] + loff,
|
||||
screen_Columns
|
||||
* sizeof(u8char_T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not redraw in pum_may_redraw() and don't draw in the area
|
||||
// where the popup menu will be.
|
||||
pum_will_redraw = TRUE;
|
||||
update_screen(0);
|
||||
pum_will_redraw = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// never display more than we have
|
||||
@@ -950,12 +1079,18 @@ pum_redraw(void)
|
||||
screen_zindex = POPUPMENU_ZINDEX;
|
||||
#endif
|
||||
|
||||
// Draw border and shadow first if enabled
|
||||
// Draw border and shadow first if enabled, before setting blend
|
||||
// so that border/shadow characters are drawn without opacity.
|
||||
if (pum_border)
|
||||
pum_draw_border();
|
||||
if (pum_shadow)
|
||||
pum_draw_shadow();
|
||||
|
||||
// Set blend for screen_puts_len / screen_fill to use.
|
||||
// Only the pum content area should be blended, not border/shadow.
|
||||
if (opacity_active)
|
||||
screen_pum_blend = 100 - (int)p_po;
|
||||
|
||||
for (i = 0; i < pum_height; ++i)
|
||||
{
|
||||
idx = i + pum_first;
|
||||
@@ -967,7 +1102,8 @@ pum_redraw(void)
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (pum_rl)
|
||||
{
|
||||
if (pum_col < curwin->w_wincol + curwin->w_width - 1 - pum_border)
|
||||
if (pum_col < curwin->w_wincol + curwin->w_width - 1
|
||||
- pum_border)
|
||||
screen_putchar(' ', row, pum_col + 1, attr);
|
||||
}
|
||||
else
|
||||
@@ -1032,8 +1168,8 @@ pum_redraw(void)
|
||||
|
||||
#ifdef FEAT_RIGHTLEFT
|
||||
if (pum_rl)
|
||||
screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ',
|
||||
' ', orig_attr);
|
||||
screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1,
|
||||
' ', ' ', orig_attr);
|
||||
else
|
||||
#endif
|
||||
screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ',
|
||||
@@ -1043,6 +1179,8 @@ pum_redraw(void)
|
||||
++row;
|
||||
}
|
||||
|
||||
screen_pum_blend = 0;
|
||||
|
||||
#ifdef FEAT_PROP_POPUP
|
||||
screen_zindex = 0;
|
||||
#endif
|
||||
@@ -1427,6 +1565,7 @@ pum_set_selected(int n, int repeat UNUSED)
|
||||
void
|
||||
pum_undisplay(void)
|
||||
{
|
||||
pum_free_bg();
|
||||
pum_array = NULL;
|
||||
redraw_all_later(UPD_NOT_VALID);
|
||||
redraw_tabline = TRUE;
|
||||
|
||||
@@ -21,6 +21,7 @@ int get_gui_attr_idx(int attr, guicolor_T fg, guicolor_T bg);
|
||||
void clear_hl_tables(void);
|
||||
int hl_combine_attr(int char_attr, int prim_attr);
|
||||
int hl_blend_attr(int char_attr, int popup_attr, int blend, int blend_fg);
|
||||
int hl_pum_blend_attr(int char_attr, int popup_attr, int blend);
|
||||
attrentry_T *syn_gui_attr2entry(int attr);
|
||||
int syn_attr2attr(int attr);
|
||||
attrentry_T *syn_term_attr2entry(int attr);
|
||||
|
||||
@@ -136,6 +136,8 @@ int expand_set_printoptions(optexpand_T *args, int *numMatches, char_u ***matche
|
||||
char *did_set_renderoptions(optset_T *args);
|
||||
char *did_set_rightleftcmd(optset_T *args);
|
||||
int expand_set_rightleftcmd(optexpand_T *args, int *numMatches, char_u ***matches);
|
||||
char *did_set_pumopt(optset_T *args);
|
||||
int expand_set_pumopt(optexpand_T *args, int *numMatches, char_u ***matches);
|
||||
char *did_set_pumborder(optset_T *args);
|
||||
int expand_set_pumborder(optexpand_T *args, int *numMatches, char_u ***matches);
|
||||
char *did_set_rulerformat(optset_T *args);
|
||||
|
||||
@@ -5,6 +5,7 @@ void pum_set_margin(int enable);
|
||||
void pum_display(pumitem_T *array, int size, int selected);
|
||||
void pum_call_update_screen(void);
|
||||
int pum_under_menu(int row, int col, int only_redrawing);
|
||||
void pum_opacity_changed(void);
|
||||
void pum_redraw(void);
|
||||
void pum_position_info_popup(win_T *wp);
|
||||
void pum_undisplay(void);
|
||||
|
||||
+28
-2
@@ -2653,6 +2653,34 @@ screen_fill(
|
||||
}
|
||||
skip_opacity_fill:
|
||||
#endif
|
||||
// For pum opacity: blend pum background with underlying.
|
||||
// Only for space cells; text cells are handled normally.
|
||||
if (screen_pum_blend > 0 && c == ' '
|
||||
&& pum_bg_attrs != NULL
|
||||
&& row >= pum_bg_top && row < pum_bg_bot
|
||||
&& col < pum_bg_cols)
|
||||
{
|
||||
int soff = (row - pum_bg_top) * pum_bg_cols + col;
|
||||
int underlying_attr = pum_bg_attrs[soff];
|
||||
|
||||
// Restore underlying character so text shows through.
|
||||
ScreenLines[off] = pum_bg_lines[soff];
|
||||
if (enc_utf8 && pum_bg_linesUC != NULL
|
||||
&& ScreenLinesUC != NULL)
|
||||
{
|
||||
int k;
|
||||
ScreenLinesUC[off] = pum_bg_linesUC[soff];
|
||||
for (k = 0; k < MAX_MCO; ++k)
|
||||
if (pum_bg_linesC[k] != NULL
|
||||
&& ScreenLinesC[k] != NULL)
|
||||
ScreenLinesC[k][off] = pum_bg_linesC[k][soff];
|
||||
}
|
||||
// Keep underlying fg, blend bg only.
|
||||
ScreenAttrs[off] = hl_pum_blend_attr(underlying_attr,
|
||||
attr, screen_pum_blend);
|
||||
screen_char(off, row, col);
|
||||
goto next_col;
|
||||
}
|
||||
#if defined(FEAT_GUI) || defined(UNIX)
|
||||
// The bold trick may make a single row of pixels appear in
|
||||
// the next character. When a bold character is removed, the
|
||||
@@ -2699,9 +2727,7 @@ skip_opacity_fill:
|
||||
if (!did_delete || c != ' ')
|
||||
screen_char(off, row, col);
|
||||
}
|
||||
#ifdef FEAT_PROP_POPUP
|
||||
next_col:
|
||||
#endif
|
||||
ScreenCols[off] = -1;
|
||||
++off;
|
||||
if (col == start_col)
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
|h+0&#ffffff0|e|l@1|o| |w|o|r|l|d| @63
|
||||
|h|e|l@1|o| |v|i|m| @65
|
||||
|h|e|l@1|o| |o|p|a|c|i|t|y| @61
|
||||
|h|e|l|p| |m|e| @67
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|h|e|l@1|o> @69
|
||||
|h+0#0000001#e0e0e08|e|l@1|o| @9| +0#4040ff13#ffffff0@59
|
||||
|h+0#0000001#ffd7ff255|e|l|p| @10| +0#4040ff13#ffffff0@59
|
||||
|~| @73
|
||||
|~| @73
|
||||
|-+2#0000000&@1| |K|e|y|w|o|r|d| |c|o|m|p|l|e|t|i|o|n| |(|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |2| +0#0000000&@33
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
|h+0&#ffffff0|e|l@1|o| |w|o|r|l|d| @63
|
||||
|h|e|l@1|o| |v|i|m| @65
|
||||
|h|e|l@1|o| |o|p|a|c|i|t|y| @61
|
||||
|h|e|l|p| |m|e| @67
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G|R|O|U|N|D|B|A|C|K|G
|
||||
|R|O|U|N|D| @69
|
||||
|h|e|l@1|o> @69
|
||||
|h+0#0000001#e0e0e08|e|l@1|o| @9| +0#4040ff13#ffffff0@59
|
||||
|h+0#0000001#ffd7ff255|e|l|p| @10| +0#4040ff13#ffffff0@59
|
||||
|~| @73
|
||||
|~| @73
|
||||
|-+2#0000000&@1| |K|e|y|w|o|r|d| |c|o|m|p|l|e|t|i|o|n| |(|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |2| +0#0000000&@33
|
||||
@@ -2420,4 +2420,50 @@ func Test_popup_shadow_hiddenchar()
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" Test pumopt opacity with screendump: background text should show through
|
||||
func Test_pumopt_opacity_screendump()
|
||||
CheckScreendump
|
||||
let lines =<< trim END
|
||||
set pumopt=opacity:50
|
||||
set completeopt=menu
|
||||
call setline(1, ['hello world', 'hello vim', 'hello opacity', 'help me'])
|
||||
for i in range(5)
|
||||
call append(line('$'), repeat('BACKGROUND', 8))
|
||||
endfor
|
||||
normal gg
|
||||
END
|
||||
call writefile(lines, 'Xpumoptopacity', 'D')
|
||||
let buf = RunVimInTerminal('-S Xpumoptopacity', {})
|
||||
call TermWait(buf)
|
||||
call term_sendkeys(buf, "Gohel\<C-N>")
|
||||
call TermWait(buf, 100)
|
||||
call VerifyScreenDump(buf, 'Test_pumopt_opacity_50', {})
|
||||
call term_sendkeys(buf, "\<C-E>\<Esc>u")
|
||||
call TermWait(buf)
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" Test pumopt opacity:100 (fully opaque, same as default)
|
||||
func Test_pumopt_opacity_100()
|
||||
CheckScreendump
|
||||
let lines =<< trim END
|
||||
set pumopt=opacity:100
|
||||
set completeopt=menu
|
||||
call setline(1, ['hello world', 'hello vim', 'hello opacity', 'help me'])
|
||||
for i in range(5)
|
||||
call append(line('$'), repeat('BACKGROUND', 8))
|
||||
endfor
|
||||
normal gg
|
||||
END
|
||||
call writefile(lines, 'Xpumoptopacity100', 'D')
|
||||
let buf = RunVimInTerminal('-S Xpumoptopacity100', {})
|
||||
call TermWait(buf)
|
||||
call term_sendkeys(buf, "Gohel\<C-N>")
|
||||
call TermWait(buf, 100)
|
||||
call VerifyScreenDump(buf, 'Test_pumopt_opacity_100', {})
|
||||
call term_sendkeys(buf, "\<C-E>\<Esc>u")
|
||||
call TermWait(buf)
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -291,6 +291,11 @@ let test_values = {
|
||||
\ 'double,margin,shadow', 'custom:─;│;─;│;┌;┐;┘;└,shadow',
|
||||
\ 'ascii,margin'],
|
||||
\ ['xxx', 'margin', 'margin,shadow', 'custom:', 'custom:+;']],
|
||||
\ 'pumopt': [['', 'border:single', 'border:double', 'border:ascii',
|
||||
\ 'height:10', 'width:20', 'maxwidth:30', 'opacity:50',
|
||||
\ 'border:double,margin,shadow',
|
||||
\ 'height:10,width:20,maxwidth:30,opacity:80'],
|
||||
\ ['xxx', 'opacity:200', 'opacity:-1', 'margin']],
|
||||
\ 'renderoptions': [[''], ['xxx']],
|
||||
\ 'rightleftcmd': [['search'], ['xxx']],
|
||||
\ 'rulerformat': [['', 'xxx'], ['%-', '%(', '%15(%%']],
|
||||
|
||||
@@ -734,6 +734,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
318,
|
||||
/**/
|
||||
317,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user