Merge pull request #29876 from glepnir/vim-patch

vim-patch:9.1.{0618,0619,0629}: cannot mark deprecated attributes in completion menu
This commit is contained in:
zeertzjq
2024-07-27 22:12:30 +08:00
committed by GitHub
7 changed files with 176 additions and 26 deletions

View File

@@ -1177,6 +1177,12 @@ items:
user_data custom data which is associated with the item and user_data custom data which is associated with the item and
available in |v:completed_item|; it can be any type; available in |v:completed_item|; it can be any type;
defaults to an empty string defaults to an empty string
hl_group an additional highlight group whose attributes are
combined with |hl-PmenuSel| and |hl-Pmenu| or
|hl-PmenuMatchSel| and |hl-PmenuMatch| highlight
attributes in the popup menu to apply cterm and gui
properties (with higher priority) like strikethrough
to the completion items
All of these except "icase", "equal", "dup" and "empty" must be a string. If All of these except "icase", "equal", "dup" and "empty" must be a string. If
an item does not meet these requirements then an error message is given and an item does not meet these requirements then an error message is given and

View File

@@ -356,6 +356,7 @@ static int cmdline_pum_create(CmdlineInfo *ccline, expand_T *xp, char **matches,
.pum_info = NULL, .pum_info = NULL,
.pum_extra = NULL, .pum_extra = NULL,
.pum_kind = NULL, .pum_kind = NULL,
.pum_user_hlattr = -1,
}; };
} }

View File

@@ -39,6 +39,7 @@
#include "nvim/globals.h" #include "nvim/globals.h"
#include "nvim/highlight.h" #include "nvim/highlight.h"
#include "nvim/highlight_defs.h" #include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h" #include "nvim/indent.h"
#include "nvim/indent_c.h" #include "nvim/indent_c.h"
#include "nvim/insexpand.h" #include "nvim/insexpand.h"
@@ -170,6 +171,7 @@ struct compl_S {
int cp_flags; ///< CP_ values int cp_flags; ///< CP_ values
int cp_number; ///< sequence number int cp_number; ///< sequence number
int cp_score; ///< fuzzy match score int cp_score; ///< fuzzy match score
int cp_user_hlattr; ///< highlight attribute to combine with
}; };
/// state information used for getting the next set of insert completion /// state information used for getting the next set of insert completion
@@ -762,7 +764,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir
flags |= CP_ICASE; flags |= CP_ICASE;
} }
int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false); int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, -1);
xfree(tofree); xfree(tofree);
return res; return res;
} }
@@ -802,7 +804,7 @@ static inline void free_cptext(char *const *const cptext)
/// returned in case of error. /// returned in case of error.
static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext, static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext,
const bool cptext_allocated, typval_T *user_data, const Direction cdir, const bool cptext_allocated, typval_T *user_data, const Direction cdir,
int flags_arg, const bool adup) int flags_arg, const bool adup, int user_hlattr)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
compl_T *match; compl_T *match;
@@ -868,6 +870,7 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
match->cp_fname = NULL; match->cp_fname = NULL;
} }
match->cp_flags = flags; match->cp_flags = flags;
match->cp_user_hlattr = user_hlattr;
if (cptext != NULL) { if (cptext != NULL) {
int i; int i;
@@ -1001,7 +1004,7 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase)
for (int i = 0; i < num_matches && add_r != FAIL; i++) { for (int i = 0; i < num_matches && add_r != FAIL; i++) {
if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir, if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
CP_FAST | (icase ? CP_ICASE : 0), CP_FAST | (icase ? CP_ICASE : 0),
false)) == OK) { false, -1)) == OK) {
// If dir was BACKWARD then honor it just once. // If dir was BACKWARD then honor it just once.
dir = FORWARD; dir = FORWARD;
} }
@@ -1268,6 +1271,7 @@ static int ins_compl_build_pum(void)
compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND]; compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
compl_match_array[i].pum_info = comp->cp_text[CPT_INFO]; compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
compl_match_array[i].pum_score = comp->cp_score; compl_match_array[i].pum_score = comp->cp_score;
compl_match_array[i].pum_user_hlattr = comp->cp_user_hlattr;
if (comp->cp_text[CPT_MENU] != NULL) { if (comp->cp_text[CPT_MENU] != NULL) {
compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU]; compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
} else { } else {
@@ -2552,6 +2556,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
bool empty = false; bool empty = false;
int flags = fast ? CP_FAST : 0; int flags = fast ? CP_FAST : 0;
char *(cptext[CPT_COUNT]); char *(cptext[CPT_COUNT]);
char *user_hlname = NULL;
int user_hlattr = -1;
typval_T user_data; typval_T user_data;
user_data.v_type = VAR_UNKNOWN; user_data.v_type = VAR_UNKNOWN;
@@ -2561,6 +2567,10 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true); cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true); cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true); cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
user_hlname = tv_dict_get_string(tv->vval.v_dict, "hl_group", false);
if (user_hlname != NULL && *user_hlname != NUL) {
user_hlattr = syn_name2attr(user_hlname);
}
tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data); tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
if (tv_dict_get_number(tv->vval.v_dict, "icase")) { if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
@@ -2582,7 +2592,7 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
return FAIL; return FAIL;
} }
int status = ins_compl_add((char *)word, -1, NULL, cptext, true, int status = ins_compl_add((char *)word, -1, NULL, cptext, true,
&user_data, dir, flags, dup); &user_data, dir, flags, dup, user_hlattr);
if (status != OK) { if (status != OK) {
tv_clear(&user_data); tv_clear(&user_data);
} }
@@ -2675,7 +2685,7 @@ static void set_completion(colnr_T startcol, list_T *list)
flags |= CP_ICASE; flags |= CP_ICASE;
} }
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
flags | CP_FAST, false) != OK) { flags | CP_FAST, false, -1) != OK) {
return; return;
} }
@@ -3420,7 +3430,7 @@ static void get_next_bufname_token(void)
char *tail = path_tail(b->b_sfname); char *tail = path_tail(b->b_sfname);
if (strncmp(tail, compl_orig_text, strlen(compl_orig_text)) == 0) { if (strncmp(tail, compl_orig_text, strlen(compl_orig_text)) == 0) {
ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0, ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0,
p_ic ? CP_ICASE : 0, false); p_ic ? CP_ICASE : 0, false, -1);
} }
} }
} }
@@ -4458,7 +4468,7 @@ static int ins_compl_start(void)
flags |= CP_ICASE; flags |= CP_ICASE;
} }
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
flags, false) != OK) { flags, false, -1) != OK) {
XFREE_CLEAR(compl_pattern); XFREE_CLEAR(compl_pattern);
compl_patternlen = 0; compl_patternlen = 0;
XFREE_CLEAR(compl_orig_text); XFREE_CLEAR(compl_orig_text);

View File

@@ -440,7 +440,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
/// Computes attributes of text on the popup menu. /// Computes attributes of text on the popup menu.
/// Returns attributes for every cell, or NULL if all attributes are the same. /// Returns attributes for every cell, or NULL if all attributes are the same.
static int *pum_compute_text_attrs(char *text, hlf_T hlf) static int *pum_compute_text_attrs(char *text, hlf_T hlf, int user_hlattr)
{ {
if ((hlf != HLF_PSI && hlf != HLF_PNI) if ((hlf != HLF_PSI && hlf != HLF_PNI)
|| (win_hl_attr(curwin, HLF_PMSI) == win_hl_attr(curwin, HLF_PSI) || (win_hl_attr(curwin, HLF_PMSI) == win_hl_attr(curwin, HLF_PSI)
@@ -487,6 +487,10 @@ static int *pum_compute_text_attrs(char *text, hlf_T hlf)
new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI); new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
} }
if (user_hlattr > 0) {
new_attr = hl_combine_attr(new_attr, user_hlattr);
}
int char_cells = utf_ptr2cells(ptr); int char_cells = utf_ptr2cells(ptr);
for (int i = 0; i < char_cells; i++) { for (int i = 0; i < char_cells; i++) {
attrs[cell_idx + i] = new_attr; attrs[cell_idx + i] = new_attr;
@@ -627,6 +631,9 @@ void pum_redraw(void)
for (int round = 0; round < 3; round++) { for (int round = 0; round < 3; round++) {
hlf = hlfs[round]; hlf = hlfs[round];
attr = win_hl_attr(curwin, (int)hlf); attr = win_hl_attr(curwin, (int)hlf);
if (pum_array[idx].pum_user_hlattr > 0) {
attr = hl_combine_attr(attr, pum_array[idx].pum_user_hlattr);
}
int width = 0; int width = 0;
char *s = NULL; char *s = NULL;
@@ -660,7 +667,8 @@ void pum_redraw(void)
*p = saved; *p = saved;
} }
int *attrs = pum_compute_text_attrs(st, hlf); int user_hlattr = pum_array[idx].pum_user_hlattr;
int *attrs = pum_compute_text_attrs(st, hlf, user_hlattr);
if (pum_rl) { if (pum_rl) {
char *rt = reverse_text(st); char *rt = reverse_text(st);

View File

@@ -16,6 +16,7 @@ typedef struct {
char *pum_info; ///< extra info char *pum_info; ///< extra info
int pum_score; ///< fuzzy match score int pum_score; ///< fuzzy match score
int pum_idx; ///< index of item before sorting by score int pum_idx; ///< index of item before sorting by score
int pum_user_hlattr; ///< highlight attribute to combine with
} pumitem_T; } pumitem_T;
EXTERN ScreenGrid pum_grid INIT( = SCREEN_GRID_INIT); EXTERN ScreenGrid pum_grid INIT( = SCREEN_GRID_INIT);

View File

@@ -1160,25 +1160,47 @@ describe('builtin popupmenu', function()
screen = Screen.new(32, 20) screen = Screen.new(32, 20)
screen:set_default_attr_ids({ screen:set_default_attr_ids({
-- popup selected item / scrollbar track -- popup selected item / scrollbar track
['s'] = { background = Screen.colors.WebGray }, s = { background = Screen.colors.Grey },
-- popup non-selected item -- popup non-selected item
['n'] = { background = Screen.colors.LightMagenta }, n = { background = Screen.colors.Plum1 },
-- popup scrollbar knob -- popup scrollbar knob
['c'] = { background = Screen.colors.Grey0 }, c = { background = Screen.colors.Black },
[1] = { bold = true, foreground = Screen.colors.Blue }, [1] = { bold = true, foreground = Screen.colors.Blue },
[2] = { bold = true }, [2] = { bold = true },
[3] = { reverse = true }, [3] = { reverse = true },
[4] = { bold = true, reverse = true }, [4] = { bold = true, reverse = true },
[5] = { bold = true, foreground = Screen.colors.SeaGreen }, [5] = { bold = true, foreground = Screen.colors.SeaGreen },
[6] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, [6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search [7] = { background = Screen.colors.Yellow }, -- Search
[8] = { foreground = Screen.colors.Red }, [8] = { foreground = Screen.colors.Red },
kn = { foreground = Screen.colors.Red, background = Screen.colors.Magenta },
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey }, ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta }, kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
mn = { foreground = Screen.colors.Blue, background = Screen.colors.Magenta }, xn = { foreground = Screen.colors.White, background = Screen.colors.Plum1 },
ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey }, ms = { foreground = Screen.colors.Blue, background = Screen.colors.Grey },
mn = { foreground = Screen.colors.Blue, background = Screen.colors.Plum1 },
ds = { foreground = Screen.colors.DarkRed, background = Screen.colors.Grey },
dn = { foreground = Screen.colors.DarkRed, background = Screen.colors.Plum1 },
ums = {
foreground = Screen.colors.Blue,
background = Screen.colors.Grey,
underline = true,
},
umn = {
foreground = Screen.colors.Blue,
background = Screen.colors.Plum1,
underline = true,
},
uds = {
foreground = Screen.colors.DarkRed,
background = Screen.colors.Grey,
underline = true,
},
udn = {
foreground = Screen.colors.DarkRed,
background = Screen.colors.Plum1,
underline = true,
},
}) })
screen:attach({ ext_multigrid = multigrid }) screen:attach({ ext_multigrid = multigrid })
end) end)
@@ -3558,7 +3580,7 @@ describe('builtin popupmenu', function()
exec([[ exec([[
set wildoptions=pum,fuzzy set wildoptions=pum,fuzzy
hi PmenuMatchSel guifg=Blue guibg=Grey hi PmenuMatchSel guifg=Blue guibg=Grey
hi PmenuMatch guifg=Blue guibg=Magenta hi PmenuMatch guifg=Blue guibg=Plum1
]]) ]])
feed(':sign plc<Tab>') feed(':sign plc<Tab>')
@@ -4704,9 +4726,9 @@ describe('builtin popupmenu', function()
-- oldtest: Test_pum_highlights_custom() -- oldtest: Test_pum_highlights_custom()
it('custom highlight groups', function() it('custom highlight groups', function()
exec([[ exec([[
hi PmenuKind guifg=Red guibg=Magenta hi PmenuKind guifg=Red guibg=Plum1
hi PmenuKindSel guifg=Red guibg=Grey hi PmenuKindSel guifg=Red guibg=Grey
hi PmenuExtra guifg=White guibg=Magenta hi PmenuExtra guifg=White guibg=Plum1
hi PmenuExtraSel guifg=Black guibg=Grey hi PmenuExtraSel guifg=Black guibg=Grey
]]) ]])
feed('iaw<C-X><C-u>') feed('iaw<C-X><C-u>')
@@ -4758,7 +4780,7 @@ describe('builtin popupmenu', function()
set omnifunc=Omni_test set omnifunc=Omni_test
set completeopt=menu,noinsert,fuzzy set completeopt=menu,noinsert,fuzzy
hi PmenuMatchSel guifg=Blue guibg=Grey hi PmenuMatchSel guifg=Blue guibg=Grey
hi PmenuMatch guifg=Blue guibg=Magenta hi PmenuMatch guifg=Blue guibg=Plum1
]]) ]])
feed('i<C-X><C-O>') feed('i<C-X><C-O>')
local pum_start = [[ local pum_start = [[
@@ -4931,6 +4953,64 @@ describe('builtin popupmenu', function()
feed('<C-E><Esc>') feed('<C-E><Esc>')
end) end)
-- oldtest: Test_pum_user_hl_group()
it('custom hl_group override', function()
exec([[
func CompleteFunc( findstart, base )
if a:findstart
return 0
endif
return {
\ 'words': [
\ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' },
\ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
\ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' },
\]}
endfunc
set completeopt=menu
set completefunc=CompleteFunc
hi StrikeFake guifg=DarkRed
func HlMatch()
hi PmenuMatchSel guifg=Blue guibg=Grey gui=underline
hi PmenuMatch guifg=Blue guibg=Plum1 gui=underline
endfunc
]])
feed('Saw<C-X><C-U>')
screen:expect([[
aword1^ |
{ds:aword1 W extra text 1 }{1: }|
{n:aword2 W extra text 2 }{1: }|
{dn:你好 W extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-E><Esc>')
command('call HlMatch()')
feed('Saw<C-X><C-U>')
screen:expect([[
aword1^ |
{uds:aw}{ds:ord1 W extra text 1 }{1: }|
{umn:aw}{n:ord2 W extra text 2 }{1: }|
{dn:你好 W extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-N>')
screen:expect([[
aword2^ |
{udn:aw}{dn:ord1 W extra text 1 }{1: }|
{ums:aw}{s:ord2 W extra text 2 }{1: }|
{dn:你好 W extra text 3 }{1: }|
{1:~ }|*15
{2:-- }{5:match 2 of 3} |
]])
feed('<C-E><Esc>')
end)
end end
end end

View File

@@ -1506,4 +1506,48 @@ func Test_pum_highlights_match()
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
func Test_pum_user_hl_group()
CheckScreendump
let lines =<< trim END
func CompleteFunc( findstart, base )
if a:findstart
return 0
endif
return {
\ 'words': [
\ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' },
\ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
\ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' },
\]}
endfunc
set completeopt=menu
set completefunc=CompleteFunc
hi StrikeFake ctermfg=9
func HlMatch()
hi PmenuMatchSel ctermfg=6 ctermbg=7 cterm=underline
hi PmenuMatch ctermfg=4 ctermbg=225 cterm=underline
endfunc
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
call TermWait(buf)
call term_sendkeys(buf, "Saw\<C-X>\<C-U>")
call VerifyScreenDump(buf, 'Test_pum_highlights_12', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call TermWait(buf)
call term_sendkeys(buf, ":call HlMatch()\<CR>")
call TermWait(buf)
call term_sendkeys(buf, "Saw\<C-X>\<C-U>")
call VerifyScreenDump(buf, 'Test_pum_highlights_13', {})
call term_sendkeys(buf, "\<C-N>")
call VerifyScreenDump(buf, 'Test_pum_highlights_14', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab