vim-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: vim/vim#17081

d4dbf822dc

Co-authored-by: glepnir <glephunter@gmail.com>
This commit is contained in:
zeertzjq
2025-04-16 07:29:44 +08:00
parent 1c723b2e6f
commit 6e5671b00d
8 changed files with 23 additions and 11 deletions

View File

@@ -2642,6 +2642,7 @@ A jump table for the options with a short description can be found at |Q_op|.
lastline '@' 'display' contains lastline/truncate lastline '@' 'display' contains lastline/truncate
trunc '>' truncated text in the trunc '>' truncated text in the
|ins-completion-menu|. |ins-completion-menu|.
truncrl '<' same as "trunc' in 'rightleft' mode
Any one that is omitted will fall back to the default. Any one that is omitted will fall back to the default.
@@ -2681,6 +2682,7 @@ A jump table for the options with a short description can be found at |Q_op|.
lastline NonText |hl-NonText| lastline NonText |hl-NonText|
trunc one of the many Popup menu highlighting groups like trunc one of the many Popup menu highlighting groups like
|hl-PmenuSel| |hl-PmenuSel|
truncrl same as "trunc"
*'findfunc'* *'ffu'* *E1514* *'findfunc'* *'ffu'* *E1514*
'findfunc' 'ffu' string (default "") 'findfunc' 'ffu' string (default "")

View File

@@ -2334,6 +2334,7 @@ vim.bo.ft = vim.bo.filetype
--- lastline '@' 'display' contains lastline/truncate --- lastline '@' 'display' contains lastline/truncate
--- trunc '>' truncated text in the --- trunc '>' truncated text in the
--- `ins-completion-menu`. --- `ins-completion-menu`.
--- truncrl '<' same as "trunc' in 'rightleft' mode
--- ---
--- Any one that is omitted will fall back to the default. --- Any one that is omitted will fall back to the default.
--- ---
@@ -2376,6 +2377,7 @@ vim.bo.ft = vim.bo.filetype
--- lastline NonText `hl-NonText` --- lastline NonText `hl-NonText`
--- trunc one of the many Popup menu highlighting groups like --- trunc one of the many Popup menu highlighting groups like
--- `hl-PmenuSel` --- `hl-PmenuSel`
--- truncrl same as "trunc"
--- ---
--- @type string --- @type string
vim.o.fillchars = "" vim.o.fillchars = ""

View File

@@ -1057,6 +1057,7 @@ typedef struct {
schar_T eob; schar_T eob;
schar_T lastline; schar_T lastline;
schar_T trunc; schar_T trunc;
schar_T truncrl;
} fcs_chars_T; } fcs_chars_T;
/// Structure which contains all information that belongs to a window. /// Structure which contains all information that belongs to a window.

View File

@@ -3062,6 +3062,7 @@ local options = {
lastline '@' 'display' contains lastline/truncate lastline '@' 'display' contains lastline/truncate
trunc '>' truncated text in the trunc '>' truncated text in the
|ins-completion-menu|. |ins-completion-menu|.
truncrl '<' same as "trunc' in 'rightleft' mode
Any one that is omitted will fall back to the default. Any one that is omitted will fall back to the default.
@@ -3101,6 +3102,7 @@ local options = {
lastline NonText |hl-NonText| lastline NonText |hl-NonText|
trunc one of the many Popup menu highlighting groups like trunc one of the many Popup menu highlighting groups like
|hl-PmenuSel| |hl-PmenuSel|
truncrl same as "trunc"
]=], ]=],
expand_cb = 'expand_set_chars_option', expand_cb = 'expand_set_chars_option',
full_name = 'fillchars', full_name = 'fillchars',

View File

@@ -2133,6 +2133,7 @@ static const struct chars_tab fcs_tab[] = {
CHARSTAB_ENTRY(&fcs_chars.eob, "eob", "~", NULL), CHARSTAB_ENTRY(&fcs_chars.eob, "eob", "~", NULL),
CHARSTAB_ENTRY(&fcs_chars.lastline, "lastline", "@", NULL), CHARSTAB_ENTRY(&fcs_chars.lastline, "lastline", "@", NULL),
CHARSTAB_ENTRY(&fcs_chars.trunc, "trunc", ">", NULL), CHARSTAB_ENTRY(&fcs_chars.trunc, "trunc", ">", NULL),
CHARSTAB_ENTRY(&fcs_chars.truncrl, "truncrl", "<", NULL),
}; };
static lcs_chars_T lcs_chars; static lcs_chars_T lcs_chars;

View File

@@ -577,7 +577,8 @@ void pum_redraw(void)
int thumb_pos = 0; int thumb_pos = 0;
int thumb_height = 1; int thumb_height = 1;
int n; int n;
schar_T fcs_trunc = curwin->w_p_fcs_chars.trunc; const schar_T fcs_trunc = pum_rl ? curwin->w_p_fcs_chars.truncrl
: curwin->w_p_fcs_chars.trunc;
// "word" "kind" "extra text" // "word" "kind" "extra text"
const hlf_T hlfsNorm[3] = { HLF_PNI, HLF_PNK, HLF_PNX }; const hlf_T hlfsNorm[3] = { HLF_PNI, HLF_PNK, HLF_PNX };
@@ -720,7 +721,9 @@ void pum_redraw(void)
char *rt = reverse_text(st); char *rt = reverse_text(st);
char *rt_start = rt; char *rt_start = rt;
int cells = (int)mb_string2cells(rt); int cells = (int)mb_string2cells(rt);
if (pum_width == p_pmw && totwidth + 1 + cells >= pum_width) { if (pum_width == p_pmw
&& (pum_width - totwidth < cells
|| (j + 1 < 3 && pum_get_item(idx, order[j + 1]) != NULL))) {
need_fcs_trunc = true; need_fcs_trunc = true;
} }
@@ -749,7 +752,9 @@ void pum_redraw(void)
grid_col -= width; grid_col -= width;
} else { } else {
int cells = (int)mb_string2cells(st); int cells = (int)mb_string2cells(st);
if (pum_width == p_pmw && totwidth + 1 + cells >= pum_width) { if (pum_width == p_pmw
&& (pum_width - totwidth < cells
|| (j + 1 < 3 && pum_get_item(idx, order[j + 1]) != NULL))) {
need_fcs_trunc = true; need_fcs_trunc = true;
} }
@@ -818,8 +823,7 @@ void pum_redraw(void)
const int lcol = col_off - pum_width + 1; const int lcol = col_off - pum_width + 1;
grid_line_fill(lcol, grid_col + 1, schar_from_ascii(' '), orig_attr); grid_line_fill(lcol, grid_col + 1, schar_from_ascii(' '), orig_attr);
if (need_fcs_trunc) { if (need_fcs_trunc) {
linebuf_char[lcol] = fcs_trunc != NUL && fcs_trunc != schar_from_ascii('>') linebuf_char[lcol] = fcs_trunc != NUL ? fcs_trunc : schar_from_ascii('<');
? fcs_trunc : schar_from_ascii('<');
if (pum_width > 1 && linebuf_char[lcol + 1] == NUL) { if (pum_width > 1 && linebuf_char[lcol + 1] == NUL) {
linebuf_char[lcol + 1] = schar_from_ascii(' '); linebuf_char[lcol + 1] = schar_from_ascii(' ');
} }

View File

@@ -5891,7 +5891,7 @@ describe('builtin popupmenu', function()
## grid 4 ## grid 4
{s:123456789>}| {s:123456789>}|
{n:一二三四 >}| {n:一二三四 >}|
{n:abcdefghi>}| {n:abcdefghij}|
{n:上下左右 }| {n:上下左右 }|
]], ]],
float_pos = { [4] = { -1, 'NW', 2, 1, 0, false, 100, 1, 1, 0 } }, float_pos = { [4] = { -1, 'NW', 2, 1, 0, false, 100, 1, 1, 0 } },
@@ -5901,7 +5901,7 @@ describe('builtin popupmenu', function()
123456789_123456789_123456789_^ | 123456789_123456789_123456789_^ |
{s:123456789>}{1: }| {s:123456789>}{1: }|
{n:一二三四 >}{1: }| {n:一二三四 >}{1: }|
{n:abcdefghi>}{1: }| {n:abcdefghij}{1: }|
{n:上下左右 }{1: }| {n:上下左右 }{1: }|
{1:~ }|*2 {1:~ }|*2
{2:-- Omni completion (^O^N^P) }{5:match 1 of 4} | {2:-- Omni completion (^O^N^P) }{5:match 1 of 4} |
@@ -5925,7 +5925,7 @@ describe('builtin popupmenu', function()
## grid 4 ## grid 4
{s:<987654321}| {s:<987654321}|
{n:< 四三二一}| {n:< 四三二一}|
{n:<ihgfedcba}| {n:jihgfedcba}|
{n: 右左下上}| {n: 右左下上}|
]], ]],
float_pos = { [4] = { -1, 'NW', 2, 1, 50, false, 100, 1, 1, 50 } }, float_pos = { [4] = { -1, 'NW', 2, 1, 50, false, 100, 1, 1, 50 } },
@@ -5935,7 +5935,7 @@ describe('builtin popupmenu', function()
^ _987654321_987654321_987654321| ^ _987654321_987654321_987654321|
{1: }{s:<987654321}| {1: }{s:<987654321}|
{1: }{n:< 四三二一}| {1: }{n:< 四三二一}|
{1: }{n:<ihgfedcba}| {1: }{n:jihgfedcba}|
{1: }{n: 右左下上}| {1: }{n: 右左下上}|
{1: ~}|*2 {1: ~}|*2
{2:-- Omni completion (^O^N^P) }{5:match 1 of 4} | {2:-- Omni completion (^O^N^P) }{5:match 1 of 4} |
@@ -6207,7 +6207,7 @@ describe('builtin popupmenu', function()
end end
feed('<Esc>') feed('<Esc>')
command('set fcs+=trunc:…') command('set fcs+=truncrl:…')
feed('S<C-X><C-O>') feed('S<C-X><C-O>')
if multigrid then if multigrid then
screen:expect({ screen:expect({

View File

@@ -2132,7 +2132,7 @@ func Test_pum_maxwidth_multibyte()
call VerifyScreenDump(buf, 'Test_pum_maxwidth_16', {'rows': 8}) call VerifyScreenDump(buf, 'Test_pum_maxwidth_16', {'rows': 8})
call term_sendkeys(buf, "\<ESC>") 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 term_sendkeys(buf, "S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_maxwidth_17', {'rows': 8}) call VerifyScreenDump(buf, 'Test_pum_maxwidth_17', {'rows': 8})
call term_sendkeys(buf, "\<ESC>") call term_sendkeys(buf, "\<ESC>")