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 <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/popupmenu.c b/src/popupmenu.c
index 556c2c3..07c99f0 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -604,10 +604,15 @@
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 @@
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 @@
}
}
- // 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 @@
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 @@
{
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 @@
}
// 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 @@
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 @@
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 9a5927a..ab37e1d 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -4714,6 +4714,7 @@
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 @@
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 9b44598..b5c898d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3851,6 +3851,7 @@
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 ada8acb..112e1f5 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 aa41b76..9f92ae7 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 d282f91..b2952fd 100644
--- a/src/testdir/test_popup.vim
+++ b/src/testdir/test_popup.vim
@@ -2126,7 +2126,7 @@
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 53b7941..6f3f241 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1296,
+/**/
1295,
/**/
1294,