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>
diff --git a/src/popupmenu.c b/src/popupmenu.c
index 14cc69a..d9ab997 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -414,7 +414,7 @@
int_u char_pos = 0;
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_PMNI] == highlight_attr[HLF_PNI]))
return NULL;
@@ -662,131 +662,129 @@
if (s == NULL)
s = 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.
- // First convert it to printable characters.
- char_u *st;
- int *attrs = NULL;
- int saved = *p;
+ width += w;
+ continue;
+ }
- if (saved != NUL)
- *p = NUL;
- st = transstr(s);
- if (saved != NUL)
- *p = saved;
+ // Display the text that fits or comes before a Tab.
+ // First convert it to printable characters.
+ char_u *st;
+ int *attrs = NULL;
+ int saved = *p;
- if (item_type == CPT_ABBR)
- attrs = pum_compute_text_attrs(st, hlf,
- pum_array[idx].pum_user_abbr_hlattr);
+ if (saved != NUL)
+ *p = NUL;
+ 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
- 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;
- int cells;
-
- cells = vim_strsize(rt);
- if (cells > pum_width)
+ do
{
- do
- {
- cells -= has_mbyte
+ cells -= has_mbyte
? (*mb_ptr2cells)(rt) : 1;
- MB_PTR_ADV(rt);
- } while (cells > pum_width);
+ MB_PTR_ADV(rt);
+ } while (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)
+ if (cells < pum_width)
{
- size -= (*mb_head_off)(st, st + size);
- cells -= (*mb_ptr2cells)(st + size);
+ // 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++;
}
- else
- --cells;
}
if (attrs == NULL)
- screen_puts_len(st, size, row, col, attr);
+ screen_puts_len(rt, (int)STRLEN(rt), row,
+ col - cells + 1, attr);
else
- pum_screen_puts_with_attrs(row, col, cells,
- st, size, attrs);
+ pum_screen_puts_with_attrs(row,
+ col - cells + 1, cells, rt,
+ (int)STRLEN(rt), attrs);
- vim_free(st);
+ vim_free(rt_start);
}
- col += width;
+ vim_free(st);
}
-
- 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;
+ col -= width;
}
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)