patch 9.1.0476: Cannot see matched text in popup menu

Problem:  Cannot see matched text in popup menu
Solution: Introduce 2 new highlighting groups: PmenuMatch and
          PmenuMatchSel (glepnir)

ping @habamax, @neutaaaaan @romainl because vim/colorschemes may need
some updates, @lifepillar for updating vim-colortemplate

closes: #14694

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
glepnir
2024-06-11 19:37:04 +02:00
committed by Christian Brabandt
parent 059cbe8933
commit 40c1c3317d
19 changed files with 405 additions and 8 deletions

View File

@ -1,4 +1,4 @@
*options.txt* For Vim version 9.1. Last change: 2024 Jun 05
*options.txt* For Vim version 9.1. Last change: 2024 Jun 11
VIM REFERENCE MANUAL by Bram Moolenaar
@ -4275,6 +4275,7 @@ A jump table for the options with a short description can be found at |Q_op|.
T:DiffText,>:SignColumn,-:Conceal,
B:SpellBad,P:SpellCap,R:SpellRare,
L:SpellLocal,+:Pmenu,=:PmenuSel,
k:PmenuMatch,<:PmenuMatchSel,
[:PmenuKind,]:PmenuKindSel,
{:PmenuExtra,}:PmenuExtraSel,
x:PmenuSbar,X:PmenuThumb,*:TabLine,
@ -4341,6 +4342,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|hl-PmenuExtraSel| } popup menu "extra" selected line
|hl-PmenuSbar| x popup menu scrollbar
|hl-PmenuThumb| X popup menu scrollbar thumb
|hl-PmenuMatch| k popup menu matched text
|hl-PmenuMatchSel| < popup menu matched text in selected line
The display modes are:
r reverse (termcap entry "mr" and "me")

View File

@ -1,4 +1,4 @@
*syntax.txt* For Vim version 9.1. Last change: 2024 Jun 09
*syntax.txt* For Vim version 9.1. Last change: 2024 Jun 11
VIM REFERENCE MANUAL by Bram Moolenaar
@ -5681,6 +5681,11 @@ PmenuExtraSel Popup menu: Selected item "extra text".
PmenuSbar Popup menu: Scrollbar.
*hl-PmenuThumb*
PmenuThumb Popup menu: Thumb of the scrollbar.
*hl-PmenuMatch*
PmenuMatch Popup menu: Matched text in normal item
*hl-PmenuMatchSel*
PmenuMatchSel Popup menu: Matched text in selected item
*hl-PopupNotification*
PopupNotification
Popup window created with |popup_notification()|. If not

View File

@ -8090,6 +8090,8 @@ hl-PmenuExtra syntax.txt /*hl-PmenuExtra*
hl-PmenuExtraSel syntax.txt /*hl-PmenuExtraSel*
hl-PmenuKind syntax.txt /*hl-PmenuKind*
hl-PmenuKindSel syntax.txt /*hl-PmenuKindSel*
hl-PmenuMatch syntax.txt /*hl-PmenuMatch*
hl-PmenuMatchSel syntax.txt /*hl-PmenuMatchSel*
hl-PmenuSbar syntax.txt /*hl-PmenuSbar*
hl-PmenuSel syntax.txt /*hl-PmenuSel*
hl-PmenuThumb syntax.txt /*hl-PmenuThumb*

View File

@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2024 Jun 05
*version9.txt* For Vim version 9.1. Last change: 2024 Jun 10
VIM REFERENCE MANUAL by Bram Moolenaar
@ -41596,6 +41596,9 @@ Autocommands: ~
Highlighting: ~
|hl-MsgArea| highlighting of the Command-line and messages area
|hl-PmenuMatch| Popup menu: highlighting of matched text
|hl-PmenuMatchSel| Popup menu: highlighting of matched text in selected
line
Commands: ~

View File

@ -258,6 +258,8 @@ static char *(highlight_init_both[]) = {
"default link CurSearch Search",
"default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel",
"default link PmenuMatch Pmenu",
"default link PmenuMatchSel PmenuSel",
"default link PmenuExtra Pmenu",
"default link PmenuExtraSel PmenuSel",
CENT("Normal cterm=NONE", "Normal gui=NONE"),

View File

@ -1431,6 +1431,15 @@ ins_compl_show_pum(void)
#define DICT_FIRST (1) // use just first element in "dict"
#define DICT_EXACT (2) // "dict" is the exact name of a file
/*
* Get current completion leader
*/
char_u *
ins_compl_leader(void)
{
return compl_leader;
}
/*
* Add any identifiers that match the given pattern "pat" in the list of
* dictionary files "dict_start" to the list of completions.

View File

@ -301,7 +301,7 @@ struct vimoption
# define ISP_LATIN1 (char_u *)"@,161-255"
#endif
# define HIGHLIGHT_INIT "8:SpecialKey,~:EndOfBuffer,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr,G:CursorLineSign,O:CursorLineFold,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine,z:StatusLineTerm,Z:StatusLineTermNC,g:MsgArea"
# define HIGHLIGHT_INIT "8:SpecialKey,~:EndOfBuffer,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr,G:CursorLineSign,O:CursorLineFold,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,k:PmenuMatch,<:PmenuMatchSel,[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine,z:StatusLineTerm,Z:StatusLineTermNC,g:MsgArea"
// Default python version for pyx* commands
#if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)

View File

@ -416,6 +416,88 @@ pum_under_menu(int row, int col, int only_redrawing)
&& col < pum_col + pum_width + pum_scrollbar;
}
/*
* displays text on the popup menu with specific attributes.
*/
static void
pum_screen_put_with_attr(int row, int col, char_u *text, int textlen, int attr)
{
int i;
int leader_len;
int char_len;
int cells;
int new_attr;
char_u *rt_leader = NULL;
char_u *match_leader = NULL;
char_u *ptr = text;
garray_T *ga = NULL;
char_u *leader = ins_compl_leader();
int in_fuzzy = (get_cot_flags() & COT_FUZZY) != 0;
if ((highlight_attr[HLF_PMSI] == highlight_attr[HLF_PSI] &&
highlight_attr[HLF_PMNI] == highlight_attr[HLF_PNI]))
{
screen_puts_len(text, textlen, row, col, attr);
return;
}
#ifdef FEAT_RIGHTLEFT
if (leader != NULL && curwin->w_p_rl)
rt_leader = reverse_text(leader);
#endif
match_leader = rt_leader != NULL ? rt_leader : leader;
leader_len = match_leader ? (int)STRLEN(match_leader) : 0;
if (match_leader != NULL && leader_len > 0 && in_fuzzy)
ga = fuzzy_match_str_with_pos(text, match_leader);
// Render text with proper attributes
while (*ptr != NUL && ptr < text + textlen)
{
char_len = mb_ptr2len(ptr);
cells = mb_ptr2cells(ptr);
new_attr = attr;
if (ga != NULL)
{
// Handle fuzzy matching
for (i = 0; i < ga->ga_len; i++)
{
int *match_pos = ((int *)ga->ga_data) + i;
int actual_char_pos = 0;
char_u *temp_ptr = text;
while (temp_ptr < ptr)
{
temp_ptr += mb_ptr2len(temp_ptr);
actual_char_pos++;
}
if (actual_char_pos == match_pos[0])
{
new_attr = highlight_attr[(attr == highlight_attr[HLF_PSI]
? HLF_PMSI : HLF_PMNI)];
break;
}
}
}
else if (!in_fuzzy && (ptr - text < leader_len) &&
(STRNCMP(text, match_leader, leader_len) == 0))
new_attr = highlight_attr[(attr == highlight_attr[HLF_PSI]
? HLF_PMSI : HLF_PMNI)];
screen_puts_len(ptr, char_len, row, col, new_attr);
col += cells;
ptr += char_len;
}
if (ga != NULL)
{
ga_clear(ga);
vim_free(ga);
}
if (rt_leader)
vim_free(rt_leader);
}
/*
* Redraw the popup menu, using "pum_first" and "pum_selected".
*/
@ -567,8 +649,7 @@ pum_redraw(void)
size++;
}
}
screen_puts_len(rt, (int)STRLEN(rt),
row, col - size + 1, attr);
pum_screen_put_with_attr(row, col -size + 1, rt, (int)STRLEN(rt), attr);
vim_free(rt_start);
}
vim_free(st);
@ -596,7 +677,7 @@ pum_redraw(void)
else
--cells;
}
screen_puts_len(st, size, row, col, attr);
pum_screen_put_with_attr(row, col, st, size, attr);
vim_free(st);
}
col += width;

View File

@ -30,6 +30,7 @@ int ins_compl_long_shown_match(void);
unsigned int get_cot_flags(void);
int pum_wanted(void);
void ins_compl_show_pum(void);
char_u *ins_compl_leader(void);
char_u *find_word_start(char_u *ptr);
char_u *find_word_end(char_u *ptr);
void ins_compl_clear(void);

View File

@ -40,6 +40,7 @@ int fuzzy_match(char_u *str, char_u *pat_arg, int matchseq, int *outScore, int_u
void f_matchfuzzy(typval_T *argvars, typval_T *rettv);
void f_matchfuzzypos(typval_T *argvars, typval_T *rettv);
int fuzzy_match_str(char_u *str, char_u *pat);
garray_T *fuzzy_match_str_with_pos(char_u *str, char_u *pat);
void fuzmatch_str_free(fuzmatch_str_T *fuzmatch, int count);
int fuzzymatches_to_strmatches(fuzmatch_str_T *fuzmatch, char_u ***matches, int count, int funcsort);
/* vim: set ft=c : */

View File

@ -5091,6 +5091,125 @@ fuzzy_match_str(char_u *str, char_u *pat)
return score;
}
/*
* Fuzzy match the position of string 'pat' in string 'str'.
* Returns a dynamic array of matching positions. If there is no match,
* returns NULL.
*/
garray_T *
fuzzy_match_str_with_pos(char_u *str UNUSED, char_u *pat UNUSED)
{
#ifdef FEAT_SEARCH_EXTRA
int score = 0;
garray_T *match_positions = ALLOC_ONE(garray_T);
typval_T tv_str;
list_T *l = NULL;
list_T *retlist = NULL;
list_T *match_str_list = NULL;
list_T *match_pos_list = NULL;
list_T *match_score_list = NULL;
listitem_T *score_item = NULL;
listitem_T *positions_item = NULL;
list_T *positions_outer_list = NULL;
listitem_T *outer_li = NULL;
list_T *positions_inner_list = NULL;
if (match_positions == NULL)
return NULL;
ga_init2(match_positions, sizeof(int), 10);
if (str == NULL || pat == NULL)
{
ga_clear(match_positions);
return NULL;
}
l = list_alloc();
if (l == NULL)
{
ga_clear(match_positions);
return NULL;
}
tv_str.v_type = VAR_STRING;
tv_str.vval.v_string = vim_strsave(str);
if (tv_str.vval.v_string == NULL || list_append_tv(l, &tv_str) == FAIL)
goto cleanup;
retlist = list_alloc();
if (retlist == NULL)
goto cleanup;
match_str_list = list_alloc();
match_pos_list = list_alloc();
match_score_list = list_alloc();
if (match_str_list == NULL || match_pos_list == NULL || match_score_list == NULL)
goto cleanup;
list_append_list(retlist, match_str_list);
list_append_list(retlist, match_pos_list);
list_append_list(retlist, match_score_list);
fuzzy_match_in_list(l, pat, FALSE, NULL, NULL, TRUE, retlist, 1);
if (retlist->lv_len != 3)
goto cleanup;
score_item = list_find(retlist, 2);
if (score_item != NULL && score_item->li_tv.v_type == VAR_LIST)
{
list_T *score_list = score_item->li_tv.vval.v_list;
if (score_list->lv_len > 0)
{
listitem_T *first_score_item = score_list->lv_first;
if (first_score_item != NULL && first_score_item->li_tv.v_type == VAR_NUMBER)
score = first_score_item->li_tv.vval.v_number;
}
}
if (score == 0)
goto cleanup;
positions_item = list_find(retlist, 1);
if (positions_item != NULL && positions_item->li_tv.v_type == VAR_LIST)
{
positions_outer_list = positions_item->li_tv.vval.v_list;
if (positions_outer_list->lv_len > 0)
{
outer_li = positions_outer_list->lv_first;
if (outer_li != NULL && outer_li->li_tv.v_type == VAR_LIST)
{
positions_inner_list = outer_li->li_tv.vval.v_list;
for (listitem_T *li = positions_inner_list->lv_first; li != NULL; li = li->li_next)
{
if (li->li_tv.v_type == VAR_NUMBER)
{
int pos = li->li_tv.vval.v_number;
ga_grow(match_positions, 1);
((int *)match_positions->ga_data)[match_positions->ga_len] = pos;
match_positions->ga_len++;
}
}
}
}
}
vim_free(tv_str.vval.v_string);
list_free(retlist);
list_free(l);
return match_positions;
cleanup:
vim_free(tv_str.vval.v_string);
list_free(match_str_list);
list_free(match_pos_list);
list_free(match_score_list);
list_free(retlist);
list_free(l);
ga_clear(match_positions);
return NULL;
#else
return NULL;
#endif
}
/*
* Free an array of fuzzy string matches "fuzmatch[count]".
*/

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o> @72
|f+0#00e0e07#ffd7ff255|o|o+0#0000001#e0e0e08| @11| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o|o+0#0000001&|b|a|r| @8| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o|o+0#0000001&|B|a|z| @8| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o|o+0#0000001&|b|a|l|a| @7| +0#4040ff13#ffffff0@59
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |8| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|你*0&#ffffff0> +&@72
|你*0#00e0e07#ffd7ff255|好*0#0000001#e0e0e08| +&@10| +0#4040ff13#ffffff0@59
|你*0#0000e05#ffd7ff255|好*0#0000001&|吗| +&@8| +0#4040ff13#ffffff0@59
|你*0#0000e05#ffd7ff255|不*0#0000001&|好|吗| +&@6| +0#4040ff13#ffffff0@59
|你*0#0000e05#ffd7ff255|可*0#0000001&|好|吗| +&@6| +0#4040ff13#ffffff0@59
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |8| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|你*0&#ffffff0|吗> +&@70
|你*0#00e0e07#ffd7ff255|好*0#0000001#e0e0e08|吗*0#00e0e07#ffd7ff255| +0#0000001#e0e0e08@8| +0#4040ff13#ffffff0@59
|你*0#0000e05#ffd7ff255|不*0#0000001&|好|吗*0#0000e05&| +0#0000001&@6| +0#4040ff13#ffffff0@59
|你*0#0000e05#ffd7ff255|可*0#0000001&|好|吗*0#0000e05&| +0#0000001&@6| +0#4040ff13#ffffff0@59
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |8| +0#0000000&@34

View File

@ -0,0 +1,20 @@
| +0&#ffffff0@70|o>f|o|f
| +0#4040ff13&@59| +0#0000001#e0e0e08@11|o|o+0#00e0e07#ffd7ff255|f
| +0#4040ff13#ffffff0@59| +0#0000001#ffd7ff255@8|r|a|b|o|o+0#0000e05&|f
| +0#4040ff13#ffffff0@59| +0#0000001#ffd7ff255@8|z|a|B|o|o+0#0000e05&|f
| +0#4040ff13#ffffff0@59| +0#0000001#ffd7ff255@7|a|l|a|b|o|o+0#0000e05&|f
| +0#4040ff13#ffffff0@73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
| @73|~
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |8| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o> @72
|f+0#00e0e07#ffd7ff255|o|o+0#0000001#e0e0e08| @11| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o|o+0#0000001&|b|a|r| @8| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o|o+0#0000001&|B|a|z| @8| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o|o+0#0000001&|b|a|l|a| @7| +0#4040ff13#ffffff0@59
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|~| @73
|-+2#0000000&@1| |O|m|n|i| |c|o|m|p|l|e|t|i|o|n| |(|^|O|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |8| +0#0000000&@34

View File

@ -1341,4 +1341,71 @@ func Test_pum_highlights_custom()
call StopVimInTerminal(buf)
endfunc
" Test match relate highlight group in pmenu
func Test_pum_highlights_match()
CheckScreendump
let lines =<< trim END
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return {
\ 'words': [
\ { 'word': 'foo',},
\ { 'word': 'foobar',},
\ { 'word': 'fooBaz',},
\ { 'word': 'foobala',},
\ { 'word': '你好',},
\ { 'word': '你好吗',},
\ { 'word': '你不好吗',},
\ { 'word': '你可好吗',},
\]}
endfunc
set omnifunc=Omni_test
set completeopt=menu,noinsert,fuzzy
hi PmenuMatchSel ctermfg=6 ctermbg=225
hi PmenuMatch ctermfg=4 ctermbg=225
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
call TermWait(buf)
call term_sendkeys(buf, "i\<C-X>\<C-O>")
call TermWait(buf, 50)
call term_sendkeys(buf, "fo")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_pum_highlights_03', {})
call term_sendkeys(buf, "\<ESC>S\<C-x>\<C-O>")
call TermWait(buf, 50)
call term_sendkeys(buf, "你")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_pum_highlights_04', {})
call term_sendkeys(buf, "吗")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_pum_highlights_05', {})
if has('rightleft')
call term_sendkeys(buf, "\<C-E>\<ESC>u:set rightleft\<CR>")
call TermWait(buf, 50)
call term_sendkeys(buf, "i\<C-X>\<C-O>")
call TermWait(buf, 50)
call term_sendkeys(buf, "fo")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_pum_highlights_06', {})
call term_sendkeys(buf, "\<C-E>\<ESC>u:set norightleft\<CR>")
call TermWait(buf)
endif
call term_sendkeys(buf, ":set completeopt-=fuzzy\<CR>")
call TermWait(buf)
call term_sendkeys(buf, "\<ESC>S\<C-x>\<C-O>")
call TermWait(buf, 50)
call term_sendkeys(buf, "fo")
call TermWait(buf, 50)
call VerifyScreenDump(buf, 'Test_pum_highlights_07', {})
call term_sendkeys(buf, "\<C-E>\<Esc>u")
call TermWait(buf)
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
476,
/**/
475,
/**/

View File

@ -1500,6 +1500,8 @@ typedef enum
, HLF_SPL // SpellLocal
, HLF_PNI // popup menu normal item
, HLF_PSI // popup menu selected item
, HLF_PMNI // popup menu matched text in normal item
, HLF_PMSI // popup menu matched text in selected item
, HLF_PNK // popup menu normal item "kind"
, HLF_PSK // popup menu selected item "kind"
, HLF_PNX // popup menu normal item "menu" (extra text)
@ -1525,7 +1527,7 @@ typedef enum
'n', 'a', 'b', 'N', 'G', 'O', 'r', 's', 'S', 'c', 't', 'v', 'V', \
'w', 'W', 'f', 'F', 'A', 'C', 'D', 'T', '-', '>', \
'B', 'P', 'R', 'L', \
'+', '=', '[', ']', '{', '}', 'x', 'X', \
'+', '=', 'k', '<','[', ']', '{', '}', 'x', 'X', \
'*', '#', '_', '!', '.', 'o', 'q', \
'z', 'Z', 'g'}