patch 9.1.1284: not possible to configure pum truncation char

Problem:  not possible to configure the completion menu truncation
          character
Solution: add the "trunc" suboption to the 'fillchars' setting to
          configure the truncation indicator (glepnir).

closes: #17006

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/popupmenu.c b/src/popupmenu.c
index 294823b..556c2c3 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -604,13 +604,10 @@
     int		last_isabbr = FALSE;
     int		orig_attr = -1;
     int		scroll_range = pum_size - pum_height;
-    int		need_ellipsis = FALSE;
-    int		char_cells = 0;
-    int		ellipsis_width = 3;
-    int		over_cell = 0;
     char_u	*new_str = NULL;
-    int		kept_len = 0;
-    char_u	*last_char = NULL;
+    char_u	*ptr = NULL;
+    int		remaining = 0;
+    int		fcs_trunc = curwin->w_fill_chars.trunc;
 
     hlf_T	hlfsNorm[3];
     hlf_T	hlfsSel[3];
@@ -727,14 +724,8 @@
 			    {
 				char_u		*rt_start = rt;
 				int		cells;
-				int		used_cells = 0;
-				char_u		*old_rt = NULL;
-				char_u		*orig_rt = NULL;
 
-				cells = mb_string2cells(rt, -1);
-				need_ellipsis = p_pmw > ellipsis_width
-						    && pum_width == p_pmw
-						    && cells > pum_width;
+				cells = mb_string2cells(rt , -1);
 				if (cells > pum_width)
 				{
 				    do
@@ -744,42 +735,7 @@
 					MB_PTR_ADV(rt);
 				    } while (cells > pum_width);
 
-				    if (need_ellipsis)
-				    {
-					orig_rt = rt;
-					while (*orig_rt != NUL)
-					{
-					    char_cells = has_mbyte ? (*mb_ptr2cells)(orig_rt) : 1;
-					    if (used_cells + char_cells > ellipsis_width)
-						break;
-					    used_cells += char_cells;
-					    MB_PTR_ADV(orig_rt);
-					    last_char = orig_rt;
-					}
-
-					if (last_char != NULL)
-					{
-					    if (used_cells < ellipsis_width)
-					    {
-						over_cell = ellipsis_width - used_cells;
-						MB_PTR_ADV(orig_rt);
-						last_char = orig_rt;
-					    }
-					    kept_len = (int)STRLEN(last_char);
-					    new_str = alloc(ellipsis_width + over_cell + kept_len + 1);
-					    if (!new_str)
-						return;
-					    vim_memset(new_str, '.', ellipsis_width);
-					    if (over_cell > 0)
-						vim_memset(new_str + ellipsis_width, ' ', over_cell);
-					    memcpy(new_str + ellipsis_width + over_cell, last_char, kept_len);
-					    new_str[ellipsis_width + kept_len + over_cell] = NUL;
-					    old_rt = rt_start;
-					    rt = rt_start = new_str;
-					    vim_free(old_rt);
-					}
-				    }
-				    else if (cells < pum_width)
+				    if (cells < pum_width)
 				    {
 					// Most left character requires 2-cells
 					// but only 1 cell is available on
@@ -790,6 +746,50 @@
 				    }
 				}
 
+				// truncated
+				if (pum_width == p_pmw
+					&& totwidth + 1 + cells >= pum_width)
+				{
+				    char_u  *orig_rt = rt;
+				    char_u  *old_rt = NULL;
+				    int	    over_cell = 0;
+				    int	    size = 0;
+
+				    remaining = pum_width - totwidth - 1;
+				    cells = mb_string2cells(rt, -1);
+				    if (cells > remaining)
+				    {
+					while (cells > remaining)
+					{
+					    MB_PTR_ADV(orig_rt);
+					    cells -= has_mbyte ? (*mb_ptr2cells)(orig_rt) : 1;
+					}
+				    }
+				    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);
+				    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;
+				}
+
 				if (attrs == NULL)
 				    screen_puts_len(rt, (int)STRLEN(rt), row,
 							col - cells + 1, attr);
@@ -809,13 +809,10 @@
 		    {
 			if (st != NULL)
 			{
-			    int		size = (int)STRLEN(st);
-			    int		cells = (*mb_string2cells)(st, size);
-			    int		used_cells = 0;
-			    char_u	*st_end = NULL;
-			    need_ellipsis = p_pmw > ellipsis_width
-					&& pum_width == p_pmw
-					&& col + cells > pum_col + pum_width;
+			    int size = (int)STRLEN(st);
+			    int cells = (*mb_string2cells)(st, size);
+			    char_u *st_end = NULL;
+			    int over_cell = 0;
 
 			    // only draw the text that fits
 			    while (size > 0
@@ -831,40 +828,46 @@
 				    --cells;
 			    }
 
-			    // Add '...' indicator if truncated due to p_pmw
-			    if (need_ellipsis)
+			    // truncated
+			    if (pum_width == p_pmw
+				    && totwidth + 1 + cells >= pum_width)
 			    {
-				st_end = st + size;
-				while (st_end > st)
+				remaining = pum_width - totwidth - 1;
+				if (cells > remaining)
 				{
-				    char_cells = has_mbyte ? (*mb_ptr2cells)(st_end) : 1;
-				    if (used_cells + char_cells > ellipsis_width)
-					break;
-				    used_cells += char_cells;
-				    MB_PTR_BACK(st, st_end);
-				    last_char = st_end;
-				}
-
-				if (last_char != NULL && st_end > st)
-				{
-				    if (used_cells < ellipsis_width)
+				    st_end = st + size;
+				    while (st_end > st && cells > remaining)
 				    {
 					MB_PTR_BACK(st, st_end);
-					last_char = st_end;
-					over_cell = ellipsis_width - used_cells;
+					cells -= has_mbyte ? (*mb_ptr2cells)(st_end) : 1;
 				    }
-				    kept_len = last_char - st;
-				    new_str = alloc(ellipsis_width + over_cell + kept_len + 1);
-				    if (!new_str)
-					return;
-				    memcpy(new_str, st, kept_len);
-				    if (over_cell > 0)
-					vim_memset(new_str + kept_len, ' ', over_cell);
-				    vim_memset(new_str + kept_len + over_cell, '.', ellipsis_width);
-				    new_str[kept_len + ellipsis_width + over_cell] = NUL;
-				    vim_free(st);
-				    st = new_str;
+				    size = st_end - st;
 				}
+
+				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;
 			    }
 
 			    if (attrs == NULL)