Merge pull request #29311 from zeertzjq/vim-9.1.0476

vim-patch:9.1.{0476,0478,0479,0480,0485}
This commit is contained in:
zeertzjq 2024-06-15 05:56:15 +08:00 committed by GitHub
commit 4b36a7e601
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 323 additions and 20 deletions

View File

@ -56,6 +56,8 @@ hi('CursorLineFold', { link = 'FoldColumn' })
hi('CurSearch', { link = 'Search' })
hi('PmenuKind', { link = 'Pmenu' })
hi('PmenuKindSel', { link = 'PmenuSel' })
hi('PmenuMatch', { link = 'Pmenu' })
hi('PmenuMatchSel', { link = 'PmenuSel' })
hi('PmenuExtra', { link = 'Pmenu' })
hi('PmenuExtraSel', { link = 'PmenuSel' })
hi('Substitute', { link = 'Search' })

View File

@ -5076,6 +5076,10 @@ 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-Question*
Question |hit-enter| prompt and yes/no questions.
*hl-QuickFixLine*

View File

@ -54,6 +54,8 @@ EXTERN const char *hlf_names[] INIT( = {
[HLF_SPL] = "SpellLocal",
[HLF_PNI] = "Pmenu",
[HLF_PSI] = "PmenuSel",
[HLF_PMNI] = "PmenuMatch",
[HLF_PMSI] = "PmenuMatchSel",
[HLF_PNK] = "PmenuKind",
[HLF_PSK] = "PmenuKindSel",
[HLF_PNX] = "PmenuExtra",

View File

@ -101,6 +101,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)

View File

@ -169,6 +169,8 @@ static const char *highlight_init_both[] = {
"default link PmenuExtraSel PmenuSel",
"default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel",
"default link PmenuMatch Pmenu",
"default link PmenuMatchSel PmenuSel",
"default link PmenuSbar Pmenu",
"default link Substitute Search",
"default link StatusLineTerm StatusLine",

View File

@ -1388,6 +1388,12 @@ bool compl_match_curr_select(int selected)
#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 *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

@ -55,13 +55,13 @@
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@: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,g:MsgArea,0:Whitespace,I:NormalNC"
"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,0:Whitespace,I:NormalNC"
// Default values for 'errorformat'.
// The "%f|%l| %m" one is used for when the contents of the quickfix window is

View File

@ -25,6 +25,7 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/extmark.h"
#include "nvim/extmark_defs.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@ -48,6 +49,7 @@
#include "nvim/plines.h"
#include "nvim/popupmenu.h"
#include "nvim/pos_defs.h"
#include "nvim/search.h"
#include "nvim/state_defs.h"
#include "nvim/strings.h"
#include "nvim/types_defs.h"
@ -435,6 +437,73 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i
pum_redraw();
}
/// Displays text on the popup menu with specific attributes.
static void pum_puts_with_attr(int col, char *text, hlf_T hlf)
{
char *leader = ins_compl_leader();
if (leader == NULL || *leader == NUL || (hlf != HLF_PSI && hlf != HLF_PNI)
|| (win_hl_attr(curwin, HLF_PMSI) == win_hl_attr(curwin, HLF_PSI)
&& win_hl_attr(curwin, HLF_PMNI) == win_hl_attr(curwin, HLF_PNI))) {
grid_line_puts(col, text, -1, win_hl_attr(curwin, (int)hlf));
return;
}
char *rt_leader = NULL;
if (curwin->w_p_rl) {
rt_leader = reverse_text(leader);
}
char *match_leader = rt_leader != NULL ? rt_leader : leader;
size_t leader_len = strlen(match_leader);
const bool in_fuzzy = (get_cot_flags() & COT_FUZZY) != 0;
garray_T *ga = NULL;
if (in_fuzzy) {
ga = fuzzy_match_str_with_pos(text, match_leader);
}
// Render text with proper attributes
const char *ptr = text;
while (*ptr != NUL) {
int char_len = utfc_ptr2len(ptr);
int cells = utf_ptr2cells(ptr);
int new_attr = win_hl_attr(curwin, (int)hlf);
if (ga != NULL) {
// Handle fuzzy matching
for (int i = 0; i < ga->ga_len; i++) {
uint32_t *match_pos = ((uint32_t *)ga->ga_data) + i;
uint32_t actual_char_pos = 0;
const char *temp_ptr = text;
while (temp_ptr < ptr) {
temp_ptr += utfc_ptr2len(temp_ptr);
actual_char_pos++;
}
if (actual_char_pos == match_pos[0]) {
new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
break;
}
}
} else if (!in_fuzzy && ptr < text + leader_len
&& strncmp(text, match_leader, leader_len) == 0) {
new_attr = win_hl_attr(curwin, hlf == HLF_PSI ? HLF_PMSI : HLF_PMNI);
}
grid_line_puts(col, ptr, char_len, new_attr);
col += cells;
ptr += char_len;
}
if (ga != NULL) {
ga_clear(ga);
xfree(ga);
}
if (rt_leader) {
xfree(rt_leader);
}
}
/// Redraw the popup menu, using "pum_first" and "pum_selected".
void pum_redraw(void)
{
@ -446,11 +515,9 @@ void pum_redraw(void)
int thumb_height = 1;
int n;
#define HA(hlf) (win_hl_attr(curwin, (hlf)))
// "word" "kind" "extra text"
const int attrsNorm[3] = { HA(HLF_PNI), HA(HLF_PNK), HA(HLF_PNX) };
const int attrsSel[3] = { HA(HLF_PSI), HA(HLF_PSK), HA(HLF_PSX) };
#undef HA
// "word" "kind" "extra text"
const hlf_T hlfsNorm[3] = { HLF_PNI, HLF_PNK, HLF_PNX };
const hlf_T hlfsSel[3] = { HLF_PSI, HLF_PSK, HLF_PSX };
int grid_width = pum_width;
int col_off = 0;
@ -517,8 +584,9 @@ void pum_redraw(void)
for (int i = 0; i < pum_height; i++) {
int idx = i + pum_first;
const int *const attrs = (idx == pum_selected) ? attrsSel : attrsNorm;
int attr = attrs[0]; // start with "word" highlight
const hlf_T *const hlfs = (idx == pum_selected) ? hlfsSel : hlfsNorm;
hlf_T hlf = hlfs[0]; // start with "word" highlight
int attr = win_hl_attr(curwin, (int)hlf);
grid_line_start(&pum_grid, row);
@ -540,7 +608,8 @@ void pum_redraw(void)
int totwidth = 0;
for (int round = 0; round < 3; round++) {
attr = attrs[round];
hlf = hlfs[round];
attr = win_hl_attr(curwin, (int)hlf);
int width = 0;
char *s = NULL;
@ -593,13 +662,12 @@ void pum_redraw(void)
size++;
}
}
grid_line_puts(grid_col - size + 1, rt, -1, attr);
pum_puts_with_attr(grid_col - size + 1, rt, hlf);
xfree(rt_start);
xfree(st);
grid_col -= width;
} else {
// use grid_line_puts() to truncate the text
grid_line_puts(grid_col, st, -1, attr);
pum_puts_with_attr(grid_col, st, hlf);
xfree(st);
grid_col += width;
}

View File

@ -21,12 +21,14 @@
#include "nvim/errors.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
@ -3542,6 +3544,37 @@ int fuzzy_match_str(char *const str, const char *const 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 *const str, const char *const pat)
{
if (str == NULL || pat == NULL) {
return NULL;
}
garray_T *match_positions = xmalloc(sizeof(garray_T));
ga_init(match_positions, sizeof(uint32_t), 10);
unsigned matches[MAX_FUZZY_MATCHES];
int score = 0;
if (!fuzzy_match(str, pat, false, &score, matches, MAX_FUZZY_MATCHES)
|| score == 0) {
ga_clear(match_positions);
xfree(match_positions);
return NULL;
}
int j = 0;
for (const char *p = pat; *p != NUL; MB_PTR_ADV(p)) {
if (!ascii_iswhite(utf_ptr2char(p))) {
GA_APPEND(uint32_t, match_positions, matches[j]);
j++;
}
}
return match_positions;
}
/// Copy a list of fuzzy matches into a string list after sorting the matches by
/// the fuzzy score. Frees the memory allocated for "fuzmatch".
void fuzzymatches_to_strmatches(fuzmatch_str_T *const fuzmatch, char ***const matches,

View File

@ -246,11 +246,11 @@ describe('ui/cursor', function()
end
end
if m.hl_id then
m.hl_id = 64
m.hl_id = 66
m.attr = { background = Screen.colors.DarkGray }
end
if m.id_lm then
m.id_lm = 71
m.id_lm = 73
end
end

View File

@ -1177,6 +1177,8 @@ describe('builtin popupmenu', function()
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
xn = { foreground = Screen.colors.White, background = Screen.colors.Magenta },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
mn = { foreground = Screen.colors.Blue, background = Screen.colors.White },
ms = { foreground = Screen.colors.Green, background = Screen.colors.White },
})
screen:attach({ ext_multigrid = multigrid })
end)
@ -4585,6 +4587,121 @@ describe('builtin popupmenu', function()
]])
end)
end)
-- oldtest: Test_pum_highlights_match()
it('can highlight matched text', function()
exec([[
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return {
\ 'words': [
\ { 'word': 'foo', 'kind': 'fookind' },
\ { 'word': 'foobar', 'kind': 'fookind' },
\ { 'word': 'fooBaz', 'kind': 'fookind' },
\ { 'word': 'foobala', 'kind': 'fookind' },
\ { 'word': '你好' },
\ { 'word': '你好吗' },
\ { 'word': '你不好吗' },
\ { 'word': '你可好吗' },
\]}
endfunc
set omnifunc=Omni_test
set completeopt=menu,noinsert,fuzzy
hi PmenuMatchSel guifg=Green guibg=White
hi PmenuMatch guifg=Blue guibg=White
]])
feed('i<C-X><C-O>')
local pum_start = [[
^ |
{s:foo fookind }{1: }|
{n:foobar fookind }{1: }|
{n:fooBaz fookind }{1: }|
{n:foobala fookind }{1: }|
{n: }{1: }|
{n: }{1: }|
{n: }{1: }|
{n: }{1: }|
{1:~ }|*10
{2:-- }{5:match 1 of 8} |
]]
screen:expect(pum_start)
feed('fo')
screen:expect([[
fo^ |
{ms:fo}{s:o fookind }{1: }|
{mn:fo}{n:obar fookind }{1: }|
{mn:fo}{n:oBaz fookind }{1: }|
{mn:fo}{n:obala fookind }{1: }|
{1:~ }|*14
{2:-- }{5:match 1 of 8} |
]])
feed('<Esc>S<C-X><C-O>')
screen:expect(pum_start)
feed('')
screen:expect([[
^ |
{ms:}{s: }{1: }|
{mn:}{n: }{1: }|
{mn:}{n: }{1: }|
{mn:}{n: }{1: }|
{1:~ }|*14
{2:-- }{5:match 1 of 8} |
]])
feed('')
screen:expect([[
^ |
{ms:}{s:}{ms:}{s: }{1: }|
{mn:}{n:}{mn:}{n: }{1: }|
{mn:}{n:}{mn:}{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 8} |
]])
feed('<C-E><Esc>')
command('set rightleft')
feed('S<C-X><C-O>')
screen:expect([[
^ |
{1: }{s: dnikoof oof}|
{1: }{n: dnikoof raboof}|
{1: }{n: dnikoof zaBoof}|
{1: }{n: dnikoof alaboof}|
{1: }{n: }|
{1: }{n: }|
{1: }{n: }|
{1: }{n: }|
{1: ~}|*10
{2:-- }{5:match 1 of 8} |
]])
feed('fo')
screen:expect([[
^ of|
{1: }{s: dnikoof o}{ms:of}|
{1: }{n: dnikoof rabo}{mn:of}|
{1: }{n: dnikoof zaBo}{mn:of}|
{1: }{n: dnikoofalabo}{mn:of}|
{1: ~}|*14
{2:-- }{5:match 1 of 8} |
]])
feed('<C-E><Esc>')
command('set norightleft')
command('set completeopt-=fuzzy')
feed('S<C-X><C-O>')
screen:expect(pum_start)
feed('fo')
screen:expect([[
fo^ |
{ms:fo}{s:o fookind }{1: }|
{mn:fo}{n:obar fookind }{1: }|
{mn:fo}{n:oBaz fookind }{1: }|
{mn:fo}{n:obala fookind }{1: }|
{1:~ }|*14
{2:-- }{5:match 1 of 8} |
]])
end)
end
end

View File

@ -1348,4 +1348,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', 'kind': 'fookind' },
\ { 'word': 'foobar', 'kind': 'fookind' },
\ { 'word': 'fooBaz', 'kind': 'fookind' },
\ { 'word': 'foobala', 'kind': 'fookind' },
\ { '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