patch 9.1.1296: completion: incorrect truncation logic

Commit: 
https://github.com/vim/vim/commit/d4dbf822dcb9fd95379bebab85def391e1179b21
Author: glepnir <glephun...@gmail.com>
Date:   Sat Apr 12 18:35:34 2025 +0200

    patch 9.1.1296: completion: incorrect truncation logic
    
    Problem:  completion: incorrect truncation logic (after: v9.1.1284)
    Solution: replace string allocation with direct screen rendering and
              fixe RTL/LTR truncation calculations (glepnir)
    
    closes: #17081
    
    Signed-off-by: glepnir <glephun...@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 9fab3f46d..089df1411 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -3621,6 +3621,7 @@ A jump table for the options with a short description can 
be found at |Q_op|.
          lastline      '@'             'display' contains lastline/truncate
          trunc         '>'             truncated text in the
                                        |ins-completion-menu|.
+         truncrl       '<'             same as "trunc' in 'rightleft' mode
 
        Any one that is omitted will fall back to the default.
 
@@ -3645,6 +3646,7 @@ A jump table for the options with a short description can 
be found at |Q_op|.
          lastline      NonText                 |hl-NonText|
          trunc         one of the many Popup menu highlighting groups like
                        |hl-PmenuSel|
+         truncrl       same as "trunc"
 
                                                *'findfunc'* *'ffu'* *E1514*
 'findfunc' 'ffu'       string  (default empty)
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 8a7f49e33..befd92ffd 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt*  For Vim version 9.1.  Last change: 2025 Apr 08
+*version9.txt*  For Vim version 9.1.  Last change: 2025 Apr 12
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -41631,6 +41631,7 @@ Options: ~
   and CTRL-D / CTRL-U for half-pagewise scrolling
 - New option value for 'fillchars':
        "trunc"         - configure truncation indicator, 'pummaxwidth'
+       "truncrl"       - like "trunc" but in 'rl' mode, 'pummaxwidth'
 
 Ex commands: ~
 - allow to specify a priority when defining a new sign |:sign-define|
diff --git a/src/popupmenu.c b/src/popupmenu.c
index 556c2c350..07c99f052 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -604,10 +604,15 @@ pum_redraw(void)
     int                last_isabbr = FALSE;
     int                orig_attr = -1;
     int                scroll_range = pum_size - pum_height;
-    char_u     *new_str = NULL;
-    char_u     *ptr = NULL;
     int                remaining = 0;
-    int                fcs_trunc = curwin->w_fill_chars.trunc;
+    int                fcs_trunc;
+
+#ifdef  FEAT_RIGHTLEFT
+    if (pum_rl)
+       fcs_trunc = curwin->w_fill_chars.truncrl;
+    else
+#endif
+       fcs_trunc = curwin->w_fill_chars.trunc;
 
     hlf_T      hlfsNorm[3];
     hlf_T      hlfsSel[3];
@@ -722,10 +727,19 @@ pum_redraw(void)
 
                            if (rt != NULL)
                            {
-                               char_u          *rt_start = rt;
-                               int             cells;
+                               char_u      *rt_start = rt;
+                               int         cells;
+                               int         over_cell = 0;
+                               int         truncated = FALSE;
 
                                cells = mb_string2cells(rt , -1);
+                               truncated = pum_width == p_pmw
+                                               && pum_width - totwidth < cells;
+
+                               if (pum_width == p_pmw && !truncated
+                                       && (j + 1 < 3 && pum_get_item(idx, 
order[j + 1]) != NULL))
+                                   truncated = TRUE;
+
                                if (cells > pum_width)
                                {
                                    do
@@ -746,13 +760,9 @@ pum_redraw(void)
                                    }
                                }
 
-                               // truncated
-                               if (pum_width == p_pmw
-                                       && totwidth + 1 + cells >= pum_width)
+                               if (truncated)
                                {
                                    char_u  *orig_rt = rt;
-                                   char_u  *old_rt = NULL;
-                                   int     over_cell = 0;
                                    int     size = 0;
 
                                    remaining = pum_width - totwidth - 1;
@@ -768,26 +778,19 @@ pum_redraw(void)
                                    size = (int)STRLEN(orig_rt);
                                    if (cells < remaining)
                                        over_cell =  remaining - cells;
-                                   new_str = alloc(size + over_cell + 1 + 
utf_char2len(fcs_trunc));
-                                   if (!new_str)
-                                       return;
-                                   ptr = new_str;
-                                   if (fcs_trunc != NUL && fcs_trunc != '>')
-                                       ptr += (*mb_char2bytes)(fcs_trunc, ptr);
+
+                                   cells = mb_string2cells(orig_rt, size);
+                                   width = cells + over_cell + 1;
+                                   rt = orig_rt;
+
+                                   if (fcs_trunc != NUL)
+                                       screen_putchar(fcs_trunc, row, col - 
width + 1, attr);
                                    else
-                                       *ptr++ = '<';
-                                   if (over_cell)
-                                   {
-                                       vim_memset(ptr, ' ', over_cell);
-                                       ptr += over_cell;
-                                   }
-                                   memcpy(ptr, orig_rt, size);
-                                   ptr[size] = NUL;
-                                   old_rt = rt_start;
-                                   rt = rt_start = new_str;
-                                   vim_free(old_rt);
-                                   cells = mb_string2cells(rt, -1);
-                                   width = cells;
+                                       screen_putchar('<', row, col - width + 
1, attr);
+
+                                   if (over_cell > 0)
+                                       screen_fill(row, row + 1, col - width + 
2,
+                                                   col - width + 2 + 
over_cell, ' ', ' ', attr);
                                }
 
                                if (attrs == NULL)
@@ -809,10 +812,16 @@ pum_redraw(void)
                    {
                        if (st != NULL)
                        {
-                           int size = (int)STRLEN(st);
-                           int cells = (*mb_string2cells)(st, size);
-                           char_u *st_end = NULL;
-                           int over_cell = 0;
+                           int         size = (int)STRLEN(st);
+                           int         cells = (*mb_string2cells)(st, size);
+                           char_u      *st_end = NULL;
+                           int         over_cell = 0;
+                           int         truncated = pum_width == p_pmw
+                                               && pum_width - totwidth < cells;
+
+                           if (pum_width == p_pmw && !truncated
+                                   && (j + 1 < 3 && pum_get_item(idx, order[j 
+ 1]) != NULL))
+                               truncated = TRUE;
 
                            // only draw the text that fits
                            while (size > 0
@@ -829,8 +838,7 @@ pum_redraw(void)
                            }
 
                            // truncated
-                           if (pum_width == p_pmw
-                                   && totwidth + 1 + cells >= pum_width)
+                           if (truncated)
                            {
                                remaining = pum_width - totwidth - 1;
                                if (cells > remaining)
@@ -846,28 +854,8 @@ pum_redraw(void)
 
                                if (cells < remaining)
                                    over_cell =  remaining - cells;
-                               new_str = alloc(size + over_cell + 1 + 
utf_char2len(fcs_trunc));
-                               if (!new_str)
-                                   return;
-                               memcpy(new_str, st, size);
-                               ptr = new_str + size;
-                               if (over_cell > 0)
-                               {
-                                   vim_memset(ptr, ' ', over_cell);
-                                   ptr += over_cell;
-                               }
-
-                               if (fcs_trunc != NUL)
-                                   ptr += (*mb_char2bytes)(fcs_trunc, ptr);
-                               else
-                                   *ptr++ = '>';
-
-                               *ptr = NUL;
-                               vim_free(st);
-                               st = new_str;
-                               cells = mb_string2cells(st, -1);
-                               size = (int)STRLEN(st);
-                               width = cells;
+                               cells = mb_string2cells(st, size);
+                               width = cells + over_cell + 1;
                            }
 
                            if (attrs == NULL)
@@ -875,6 +863,18 @@ pum_redraw(void)
                            else
                                pum_screen_puts_with_attrs(row, col, cells,
                                                              st, size, attrs);
+                           if (truncated)
+                           {
+                               if (over_cell > 0)
+                                   screen_fill(row, row + 1, col + cells,
+                                           col + cells + over_cell, ' ', ' ', 
attr);
+                               if (fcs_trunc != NUL)
+                                   screen_putchar(fcs_trunc, row,
+                                           col + cells + over_cell, attr);
+                               else
+                                   screen_putchar('>', row,
+                                           col + cells + over_cell, attr);
+                           }
 
                            vim_free(st);
                        }
diff --git a/src/screen.c b/src/screen.c
index 9a5927abe..ab37e1d61 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -4714,6 +4714,7 @@ static struct charstab filltab[] =
     CHARSTAB_ENTRY(&fill_chars.eob,        "eob"),
     CHARSTAB_ENTRY(&fill_chars.lastline,    "lastline"),
     CHARSTAB_ENTRY(&fill_chars.trunc,      "trunc"),
+    CHARSTAB_ENTRY(&fill_chars.truncrl,            "truncrl"),
 };
 static lcs_chars_T lcs_chars;
 static struct charstab lcstab[] =
@@ -4828,6 +4829,7 @@ set_chars_option(win_T *wp, char_u *value, int 
is_listchars, int apply,
                fill_chars.eob = '~';
                fill_chars.lastline = '@';
                fill_chars.trunc = '>';
+               fill_chars.truncrl = '<';
            }
        }
        p = value;
diff --git a/src/structs.h b/src/structs.h
index 9b44598ac..b5c898d16 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3851,6 +3851,7 @@ typedef struct
     int        eob;
     int        lastline;
     int trunc;
+    int truncrl;
 } fill_chars_T;
 
 /*
diff --git a/src/testdir/dumps/Test_pum_maxwidth_07.dump 
b/src/testdir/dumps/Test_pum_maxwidth_07.dump
index ada8acb0d..112e1f588 100644
--- a/src/testdir/dumps/Test_pum_maxwidth_07.dump
+++ b/src/testdir/dumps/Test_pum_maxwidth_07.dump
@@ -1,7 +1,7 @@
 |1+0&#ffffff0|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_|1|2|3|4|5|6|7|8|9|_> @44
 |1+0#0000001#e0e0e08|2|3|4|5|6|7|8|9|>| +0#4040ff13#ffffff0@64
 |一*0#0000001#ffd7ff255|二|三|四| +&|>| +0#4040ff13#ffffff0@64
-|a+0#0000001#ffd7ff255|b|c|d|e|f|g|h|i|>| +0#4040ff13#ffffff0@64
+|a+0#0000001#ffd7ff255|b|c|d|e|f|g|h|i|j| +0#4040ff13#ffffff0@64
 |上*0#0000001#ffd7ff255|下|左|右| +&@1| +0#4040ff13#ffffff0@64
 |~| @73
 |~| @73
diff --git a/src/testdir/dumps/Test_pum_maxwidth_08.dump 
b/src/testdir/dumps/Test_pum_maxwidth_08.dump
index aa41b76d1..9f92ae706 100644
--- a/src/testdir/dumps/Test_pum_maxwidth_08.dump
+++ b/src/testdir/dumps/Test_pum_maxwidth_08.dump
@@ -1,7 +1,7 @@
 | +0&#ffffff0@43> |_|9|8|7|6|5|4|3|2|1|_|9|8|7|6|5|4|3|2|1|_|9|8|7|6|5|4|3|2|1
 | +0#4040ff13&@64|<+0#0000001#e0e0e08|9|8|7|6|5|4|3|2|1
 | +0#4040ff13#ffffff0@64|<+0#0000001#ffd7ff255| |四*&|三|二|一
-| +0#4040ff13#ffffff0@64|<+0#0000001#ffd7ff255|i|h|g|f|e|d|c|b|a
+| +0#4040ff13#ffffff0@64|j+0#0000001#ffd7ff255|i|h|g|f|e|d|c|b|a
 | +0#4040ff13#ffffff0@64| +0#0000001#ffd7ff255@1|右*&|左|下|上
 | +0#4040ff13#ffffff0@73|~
 | @73|~
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
index d282f91cf..b2952fdc3 100644
--- a/src/testdir/test_popup.vim
+++ b/src/testdir/test_popup.vim
@@ -2126,7 +2126,7 @@ func Test_pum_maxwidth_multibyte()
     call VerifyScreenDump(buf, 'Test_pum_maxwidth_16', {'rows': 8})
     call term_sendkeys(buf, "\<ESC>")
 
-    call term_sendkeys(buf, ":set fcs+=trunc:…\<CR>")
+    call term_sendkeys(buf, ":set fcs+=truncrl:…\<CR>")
     call term_sendkeys(buf, "S\<C-X>\<C-O>")
     call VerifyScreenDump(buf, 'Test_pum_maxwidth_17', {'rows': 8})
     call term_sendkeys(buf, "\<ESC>")
diff --git a/src/version.c b/src/version.c
index 53b794173..6f3f24178 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 */
+/**/
+    1296,
 /**/
     1295,
 /**/

-- 
-- 
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/E1u3dyZ-00GOwy-AO%40256bit.org.

Raspunde prin e-mail lui