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.

Raspunde prin e-mail lui