patch 9.1.1011: popupmenu internal error with some abbr in completion item Commit: https://github.com/vim/vim/commit/3a0cc36c69744a7727ce34311d39d2d9d8ddc6f9 Author: zeertzjq <zeert...@outlook.com> Date: Mon Jan 13 07:27:43 2025 +0100
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 <zeert...@outlook.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/src/popupmenu.c b/src/popupmenu.c index 14cc69a86..d9ab997bf 100644 --- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -414,7 +414,7 @@ pum_compute_text_attrs(char_u *text, hlf_T hlf, int user_hlattr) 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 @@ pum_redraw(void) 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; - - 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); + width += w; + continue; + } + + // 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 (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); - - 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++; - } + 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, + 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); + (int)STRLEN(rt), attrs); - vim_free(rt_start); - } - vim_free(st); + vim_free(rt_start); } - col -= width; + vim_free(st); } - else + col -= width; + } + else #endif + { + if (st != NULL) { - if (st != NULL) - { - int size = (int)STRLEN(st); - int cells = (*mb_string2cells)(st, size); + int size = (int)STRLEN(st); + int cells = (*mb_string2cells)(st, size); - // only draw the text that fits - while (size > 0 + // only draw the text that fits + while (size > 0 && col + cells > pum_width + pum_col) + { + --size; + if (has_mbyte) { - --size; - if (has_mbyte) - { - size -= (*mb_head_off)(st, st + size); - cells -= (*mb_ptr2cells)(st + size); - } - else - --cells; + size -= (*mb_head_off)(st, st + size); + cells -= (*mb_ptr2cells)(st + size); } - - if (attrs == NULL) - screen_puts_len(st, size, row, col, attr); else - pum_screen_puts_with_attrs(row, col, cells, + --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; + vim_free(st); } + col += width; + } - if (attrs != NULL) - VIM_CLEAR(attrs); + if (attrs != NULL) + VIM_CLEAR(attrs); - if (*p != TAB) - break; + if (*p != TAB) + break; - // Display two spaces for a Tab. + // 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 (pum_rl) + { + screen_puts_len((char_u *)" ", 2, row, col - 1, attr); + col -= 2; } else - width += w; +#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) diff --git a/src/testdir/dumps/Test_pum_highlights_19.dump b/src/testdir/dumps/Test_pum_highlights_19.dump new file mode 100644 index 000000000..4cb353447 --- /dev/null +++ b/src/testdir/dumps/Test_pum_highlights_19.dump @@ -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 diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index d4d1c2fed..fb5d07b39 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -1528,6 +1528,39 @@ func Test_pum_highlights_match() call StopVimInTerminal(buf) 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 !" }, + \ { 'word': 'foobaz', 'abbr': "foobaz !" }, + \]} + 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() CheckScreendump let lines =<< trim END diff --git a/src/version.c b/src/version.c index b7a22dd49..a008d3240 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1011, /**/ 1010, /**/ -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1tXDxe-008it7-CF%40256bit.org.