1
0
forked from aniani/vim

patch 9.1.1011: popupmenu internal error with some abbr in completion item

Problem:  Popup menu internal error with some abbr in completion item.
Solution: Don't compute attributes when there is no corresponding text.
          Reduce indent in pum_redraw() while at it (zeertzjq).

fixes: #16427
closes: #16435

Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
zeertzjq
2025-01-13 07:27:43 +01:00
committed by Christian Brabandt
parent c200f53cbb
commit 3a0cc36c69
4 changed files with 157 additions and 104 deletions

View File

@@ -414,7 +414,7 @@ pum_compute_text_attrs(char_u *text, hlf_T hlf, int user_hlattr)
int_u char_pos = 0; int_u char_pos = 0;
int is_select = FALSE; int is_select = FALSE;
if ((hlf != HLF_PSI && hlf != HLF_PNI) if (*text == NUL || (hlf != HLF_PSI && hlf != HLF_PNI)
|| (highlight_attr[HLF_PMSI] == highlight_attr[HLF_PSI] || (highlight_attr[HLF_PMSI] == highlight_attr[HLF_PSI]
&& highlight_attr[HLF_PMNI] == highlight_attr[HLF_PNI])) && highlight_attr[HLF_PMNI] == highlight_attr[HLF_PNI]))
return NULL; return NULL;
@@ -662,131 +662,129 @@ pum_redraw(void)
if (s == NULL) if (s == NULL)
s = p; s = p;
w = ptr2cells(p); w = ptr2cells(p);
if (*p == NUL || *p == TAB || totwidth + w > pum_width) if (*p != NUL && *p != TAB && totwidth + w <= pum_width)
{ {
// Display the text that fits or comes before a Tab. width += w;
// First convert it to printable characters. continue;
char_u *st; }
int *attrs = NULL;
int saved = *p;
if (saved != NUL) // Display the text that fits or comes before a Tab.
*p = NUL; // First convert it to printable characters.
st = transstr(s); char_u *st;
if (saved != NUL) int *attrs = NULL;
*p = saved; int saved = *p;
if (item_type == CPT_ABBR) if (saved != NUL)
attrs = pum_compute_text_attrs(st, hlf, *p = NUL;
pum_array[idx].pum_user_abbr_hlattr); st = transstr(s);
if (saved != NUL)
*p = saved;
if (item_type == CPT_ABBR)
attrs = pum_compute_text_attrs(st, hlf,
pum_array[idx].pum_user_abbr_hlattr);
#ifdef FEAT_RIGHTLEFT #ifdef FEAT_RIGHTLEFT
if (pum_rl) if (pum_rl)
{
if (st != NULL)
{ {
if (st != NULL) char_u *rt = reverse_text(st);
if (rt != NULL)
{ {
char_u *rt = reverse_text(st); char_u *rt_start = rt;
int cells;
if (rt != NULL) cells = vim_strsize(rt);
if (cells > pum_width)
{ {
char_u *rt_start = rt; do
int cells;
cells = vim_strsize(rt);
if (cells > pum_width)
{ {
do cells -= has_mbyte
{
cells -= has_mbyte
? (*mb_ptr2cells)(rt) : 1; ? (*mb_ptr2cells)(rt) : 1;
MB_PTR_ADV(rt); MB_PTR_ADV(rt);
} while (cells > pum_width); } while (cells > pum_width);
if (cells < pum_width) if (cells < pum_width)
{
// Most left character requires
// 2-cells but only 1 cell is
// available on screen. Put a
// '<' on the left of the pum
// item
*(--rt) = '<';
cells++;
}
}
if (attrs == NULL)
screen_puts_len(rt, (int)STRLEN(rt),
row, col - cells + 1, attr);
else
pum_screen_puts_with_attrs(row,
col - cells + 1, cells, rt,
(int)STRLEN(rt), attrs);
vim_free(rt_start);
}
vim_free(st);
}
col -= width;
}
else
#endif
{
if (st != NULL)
{
int size = (int)STRLEN(st);
int cells = (*mb_string2cells)(st, size);
// only draw the text that fits
while (size > 0
&& col + cells > pum_width + pum_col)
{
--size;
if (has_mbyte)
{ {
size -= (*mb_head_off)(st, st + size); // Most left character requires 2-cells
cells -= (*mb_ptr2cells)(st + size); // but only 1 cell is available on
// screen. Put a '<' on the left of
// the pum item.
*(--rt) = '<';
cells++;
} }
else
--cells;
} }
if (attrs == NULL) if (attrs == NULL)
screen_puts_len(st, size, row, col, attr); screen_puts_len(rt, (int)STRLEN(rt), row,
col - cells + 1, attr);
else else
pum_screen_puts_with_attrs(row, col, cells, pum_screen_puts_with_attrs(row,
st, size, attrs); col - cells + 1, cells, rt,
(int)STRLEN(rt), attrs);
vim_free(st); vim_free(rt_start);
} }
col += width; vim_free(st);
} }
col -= width;
if (attrs != NULL)
VIM_CLEAR(attrs);
if (*p != TAB)
break;
// Display two spaces for a Tab.
#ifdef FEAT_RIGHTLEFT
if (pum_rl)
{
screen_puts_len((char_u *)" ", 2, row, col - 1,
attr);
col -= 2;
}
else
#endif
{
screen_puts_len((char_u *)" ", 2, row, col,
attr);
col += 2;
}
totwidth += 2;
s = NULL; // start text at next char
width = 0;
} }
else else
width += w; #endif
{
if (st != NULL)
{
int size = (int)STRLEN(st);
int cells = (*mb_string2cells)(st, size);
// only draw the text that fits
while (size > 0
&& col + cells > pum_width + pum_col)
{
--size;
if (has_mbyte)
{
size -= (*mb_head_off)(st, st + size);
cells -= (*mb_ptr2cells)(st + size);
}
else
--cells;
}
if (attrs == NULL)
screen_puts_len(st, size, row, col, attr);
else
pum_screen_puts_with_attrs(row, col, cells,
st, size, attrs);
vim_free(st);
}
col += width;
}
if (attrs != NULL)
VIM_CLEAR(attrs);
if (*p != TAB)
break;
// Display two spaces for a Tab.
#ifdef FEAT_RIGHTLEFT
if (pum_rl)
{
screen_puts_len((char_u *)" ", 2, row, col - 1, attr);
col -= 2;
}
else
#endif
{
screen_puts_len((char_u *)" ", 2, row, col, attr);
col += 2;
}
totwidth += 2;
s = NULL; // start text at next char
width = 0;
} }
if (j > 0) if (j > 0)

View File

@@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|f+0#00e0e07#e0e0e08|o@1|b+0#0000001&|a|r| @3|!| @3| +0#4040ff13#ffffff0@59
|f+0#0000e05#ffd7ff255|o@1|b+0#0000001&|a|z| @3|!| @3| +0#4040ff13#ffffff0@59
|~| @73
|~| @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| |2| +0#0000000&@34

View File

@@ -1528,6 +1528,39 @@ func Test_pum_highlights_match()
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
func Test_pum_highlights_match_with_abbr()
CheckScreendump
let lines =<< trim END
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return {
\ 'words': [
\ { 'word': 'foobar', 'abbr': "foobar\t\t!" },
\ { 'word': 'foobaz', 'abbr': "foobaz\t\t!" },
\]}
endfunc
set omnifunc=Omni_test
set completeopt=menuone,noinsert
hi PmenuMatchSel ctermfg=6 ctermbg=7
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, "foo")
call VerifyScreenDump(buf, 'Test_pum_highlights_19', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call TermWait(buf)
call StopVimInTerminal(buf)
endfunc
func Test_pum_user_abbr_hlgroup() func Test_pum_user_abbr_hlgroup()
CheckScreendump CheckScreendump
let lines =<< trim END let lines =<< trim END

View File

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