0
0
mirror of https://github.com/vim/vim.git synced 2025-08-31 20:53:42 -04:00

patch 9.1.0754: fixed order of items in insert-mode completion menu

Problem:  fixed order of items in insert-mode completion menu
Solution: Introduce the 'completeitemalign' option with default
          value "abbr,kind,menu" (glepnir).

Adding an new option `completeitemalign` abbr is `cia` to custom
the complete-item order in popupmenu.

closes: #14006
closes: #15760

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
glepnir 2024-10-01 20:32:12 +02:00 committed by Christian Brabandt
parent e021f39b79
commit 6a89c94a9e
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
20 changed files with 326 additions and 41 deletions

View File

@ -2102,6 +2102,16 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
*'completeitemalign'* *'cia'*
'completeitemalign' 'cia' string (default: "abbr,kind,menu")
global
A comma-separated list of |complete-items| that controls the alignment
and display order of items in the popup menu during Insert mode
completion. The supported values are abbr, kind, and menu. These
options allow to customize how the completion items are shown in the
popup menu. Note: must always contain those three values in any
order.
*'completeopt'* *'cot'*
'completeopt' 'cot' string (default: "menu,preview")
global or local to buffer |global-local|

View File

@ -134,6 +134,7 @@ $quote eval.txt /*$quote*
'character' intro.txt /*'character'*
'charconvert' options.txt /*'charconvert'*
'ci' options.txt /*'ci'*
'cia' options.txt /*'cia'*
'cin' options.txt /*'cin'*
'cindent' options.txt /*'cindent'*
'cink' options.txt /*'cink'*
@ -161,6 +162,7 @@ $quote eval.txt /*$quote*
'compatible' options.txt /*'compatible'*
'complete' options.txt /*'complete'*
'completefunc' options.txt /*'completefunc'*
'completeitemalign' options.txt /*'completeitemalign'*
'completeopt' options.txt /*'completeopt'*
'completepopup' options.txt /*'completepopup'*
'completeslash' options.txt /*'completeslash'*

View File

@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2024 Sep 23
*version9.txt* For Vim version 9.1. Last change: 2024 Oct 01
VIM REFERENCE MANUAL by Bram Moolenaar
@ -41642,6 +41642,8 @@ Commands: ~
Options: ~
'completeitemalign' Order of |complete-items| in Insert mode completion
popup
'winfixbuf' Keep buffer focused in a window
'tabclose' Which tab page to focus after closing a tab page
't_xo' Terminal uses XON/XOFF handshaking (e.g. vt420)

View File

@ -849,6 +849,8 @@ if has("insert_expand")
call <SID>OptionL("cpt")
call <SID>AddOption("completeopt", gettext("whether to use a popup menu for Insert mode completion"))
call <SID>OptionL("cot")
call <SID>AddOption("completeitemalign", gettext("popup menu item align order"))
call <SID>OptionG("cia", &cia)
if exists("+completepopup")
call <SID>AddOption("completepopup", gettext("options for the Insert mode completion info popup"))
call <SID>OptionG("cpp", &cpp)

View File

@ -87,15 +87,6 @@ static char *ctrl_x_mode_names[] = {
};
#endif
/*
* Array indexes used for cp_text[].
*/
#define CPT_ABBR 0 // "abbr"
#define CPT_MENU 1 // "menu"
#define CPT_KIND 2 // "kind"
#define CPT_INFO 3 // "info"
#define CPT_COUNT 4 // Number of entries
/*
* Structure used to store one match for insert completion.
*/
@ -1338,8 +1329,7 @@ ins_compl_build_pum(void)
}
if (compl->cp_text[CPT_ABBR] != NULL)
compl_match_array[i].pum_text =
compl->cp_text[CPT_ABBR];
compl_match_array[i].pum_text = compl->cp_text[CPT_ABBR];
else
compl_match_array[i].pum_text = compl->cp_str;
compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];

View File

@ -513,6 +513,8 @@ EXTERN char_u *p_cpt; // 'complete'
EXTERN int p_confirm; // 'confirm'
#endif
EXTERN int p_cp; // 'compatible'
EXTERN char_u *p_cia; // 'completeitemalign'
EXTERN unsigned cia_flags; // order flags of 'completeitemalign'
EXTERN char_u *p_cot; // 'completeopt'
EXTERN unsigned cot_flags; // flags from 'completeopt'
// Keep in sync with p_cot_values in optionstr.c

View File

@ -653,6 +653,10 @@ static struct vimoption options[] =
{(char_u *)0L, (char_u *)0L}
#endif
SCTX_INIT},
{"completeitemalign", "cia", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
(char_u *)&p_cia, PV_NONE, did_set_completeitemalign, NULL,
{(char_u *)"abbr,kind,menu", (char_u *)0L}
SCTX_INIT},
{"completeopt", "cot", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
(char_u *)&p_cot, PV_COT, did_set_completeopt, expand_set_completeopt,
{(char_u *)"menu,preview", (char_u *)0L}

View File

@ -1635,6 +1635,58 @@ expand_set_completeopt(optexpand_T *args, int *numMatches, char_u ***matches)
matches);
}
/*
* The 'completeitemalign' option is changed.
*/
char *
did_set_completeitemalign(optset_T *args UNUSED)
{
char_u *p = p_cia;
unsigned new_cia_flags = 0;
int seen[3] = { FALSE, FALSE, FALSE };
int count = 0;
char_u buf[10];
while (*p)
{
copy_option_part(&p, buf, sizeof(buf), ",");
if (count >= 3)
return e_invalid_argument;
if (STRCMP(buf, "abbr") == 0)
{
if (seen[CPT_ABBR])
return e_invalid_argument;
new_cia_flags = new_cia_flags * 10 + CPT_ABBR;
seen[CPT_ABBR] = TRUE;
count++;
}
else if (STRCMP(buf, "kind") == 0)
{
if (seen[CPT_KIND])
return e_invalid_argument;
new_cia_flags = new_cia_flags * 10 + CPT_KIND;
seen[CPT_KIND] = TRUE;
count++;
}
else if (STRCMP(buf, "menu") == 0)
{
if (seen[CPT_MENU])
return e_invalid_argument;
new_cia_flags = new_cia_flags * 10 + CPT_MENU;
seen[CPT_MENU] = TRUE;
count++;
}
else
return e_invalid_argument;
}
if (new_cia_flags == 0 || count != 3)
return e_invalid_argument;
cia_flags = new_cia_flags;
return NULL;
}
#if (defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX)) || defined(PROTO)
/*
* The 'completepopup' option is changed.

View File

@ -536,6 +536,28 @@ pum_screen_puts_with_attrs(
}
}
static inline void
pum_align_order(int *order)
{
int is_default = cia_flags == 0;
order[0] = is_default ? CPT_ABBR : cia_flags / 100;
order[1] = is_default ? CPT_KIND : (cia_flags / 10) % 10;
order[2] = is_default ? CPT_MENU : cia_flags % 10;
}
static inline char_u *
pum_get_item(int index, int type)
{
switch(type)
{
case CPT_ABBR: return pum_array[index].pum_text;
case CPT_KIND: return pum_array[index].pum_kind;
case CPT_MENU: return pum_array[index].pum_extra;
}
return NULL;
}
/*
* Redraw the popup menu, using "pum_first" and "pum_selected".
*/
@ -549,19 +571,25 @@ pum_redraw(void)
hlf_T *hlfs; // array used for highlights
hlf_T hlf;
int attr;
int i;
int i, j;
int idx;
char_u *s;
char_u *p = NULL;
int totwidth, width, w;
int totwidth, width, w; // total-width item-width char-width
int thumb_pos = 0;
int thumb_height = 1;
int round;
int item_type;
int order[3];
int next_isempty = FALSE;
int n;
int items_width_array[3] = { pum_base_width, pum_kind_width,
pum_extra_width };
int basic_width; // first item width
int last_isabbr = FALSE;
hlf_T hlfsNorm[3];
hlf_T hlfsSel[3];
// "word"
// "word"/"abbr"
hlfsNorm[0] = HLF_PNI;
hlfsSel[0] = HLF_PSI;
// "kind"
@ -621,28 +649,24 @@ pum_redraw(void)
screen_putchar(' ', row, pum_col - 1, attr);
// Display each entry, use two spaces for a Tab.
// Do this 3 times:
// 0 - main text
// 1 - kind
// 2 - extra info
// Do this 3 times and order from p_cia
col = pum_col;
totwidth = 0;
for (round = 0; round < 3; ++round)
pum_align_order(order);
basic_width = items_width_array[order[0]];
last_isabbr = order[2] == CPT_ABBR;
for (j = 0; j < 3; ++j)
{
hlf = hlfs[round];
item_type = order[j];
hlf = hlfs[item_type];
attr = highlight_attr[hlf];
if (pum_array[idx].pum_user_hlattr > 0)
attr = hl_combine_attr(attr, pum_array[idx].pum_user_hlattr);
if (round == 1 && pum_array[idx].pum_user_kind_hlattr > 0)
if (item_type == CPT_KIND && pum_array[idx].pum_user_kind_hlattr > 0)
attr = hl_combine_attr(attr, pum_array[idx].pum_user_kind_hlattr);
width = 0;
s = NULL;
switch (round)
{
case 0: p = pum_array[idx].pum_text; break;
case 1: p = pum_array[idx].pum_kind; break;
case 2: p = pum_array[idx].pum_extra; break;
}
p = pum_get_item(idx, item_type);
if (p != NULL)
for ( ; ; MB_PTR_ADV(p))
{
@ -774,33 +798,35 @@ pum_redraw(void)
width += w;
}
if (round > 0)
n = pum_kind_width + 1;
if (j > 0)
n = items_width_array[order[1]] + (last_isabbr ? 0 : 1);
else
n = 1;
n = order[j] == CPT_ABBR ? 1 : 0;
if (j + 1 < 3)
next_isempty = pum_get_item(idx, order[j + 1]) == NULL;
// Stop when there is nothing more to display.
if (round == 2
|| (round == 1 && pum_array[idx].pum_extra == NULL)
|| (round == 0 && pum_array[idx].pum_kind == NULL
&& pum_array[idx].pum_extra == NULL)
if (j == 2
|| (next_isempty && (j == 1 || (j == 0
&& pum_get_item(idx, order[j + 2]) == NULL)))
|| pum_base_width + n >= pum_width)
break;
#ifdef FEAT_RIGHTLEFT
if (pum_rl)
{
screen_fill(row, row + 1, pum_col - pum_base_width - n + 1,
screen_fill(row, row + 1, pum_col - basic_width - n + 1,
col + 1, ' ', ' ', attr);
col = pum_col - pum_base_width - n;
col = pum_col - basic_width - n;
}
else
#endif
{
screen_fill(row, row + 1, col, pum_col + pum_base_width + n,
screen_fill(row, row + 1, col, pum_col + basic_width + n,
' ', ' ', attr);
col = pum_col + pum_base_width + n;
col = pum_col + basic_width + n;
}
totwidth = pum_base_width + n;
totwidth = basic_width + n;
}
#ifdef FEAT_RIGHTLEFT

View File

@ -42,6 +42,7 @@ char *did_set_complete(optset_T *args);
int expand_set_complete(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_completeopt(optset_T *args);
int expand_set_completeopt(optexpand_T *args, int *numMatches, char_u ***matches);
char *did_set_completeitemalign(optset_T *args);
char *did_set_completepopup(optset_T *args);
char *did_set_completeslash(optset_T *args);
int expand_set_completeslash(optexpand_T *args, int *numMatches, char_u ***matches);

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|f+0#0000001#e0e0e08|o@1| @1|S| |m|e|n|u| @3| +0#4040ff13#ffffff0@59
|b+0#0000001#ffd7ff255|a|r| @1|T| |m|e|n|u| @3| +0#4040ff13#ffffff0@59
|你*0#0000001#ffd7ff255|好| +&|C| |中*&|文| +&@3| +0#4040ff13#ffffff0@59
|~| @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| |3| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|f+0#0000001#e0e0e08|o@1| @1|m|e|n|u| |S| @3| +0#4040ff13#ffffff0@59
|b+0#0000001#ffd7ff255|a|r| @1|m|e|n|u| |T| @3| +0#4040ff13#ffffff0@59
|你*0#0000001#ffd7ff255|好| +&|中*&|文| +&|C| @3| +0#4040ff13#ffffff0@59
|~| @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| |3| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|S+0#0000001#e0e0e08| |f|o@1| @1|m|e|n|u| @3| +0#4040ff13#ffffff0@59
|T+0#0000001#ffd7ff255| |b|a|r| @1|m|e|n|u| @3| +0#4040ff13#ffffff0@59
|C+0#0000001#ffd7ff255| |你*&|好| +&|中*&|文| +&@3| +0#4040ff13#ffffff0@59
|~| @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| |3| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|S+0#0000001#e0e0e08| |m|e|n|u| |f|o@1| @4| +0#4040ff13#ffffff0@59
|T+0#0000001#ffd7ff255| |m|e|n|u| |b|a|r| @4| +0#4040ff13#ffffff0@59
|C+0#0000001#ffd7ff255| |中*&|文| +&|你*&|好| +&@3| +0#4040ff13#ffffff0@59
|~| @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| |3| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|m+0#0000001#e0e0e08|e|n|u| |f|o@1| @1|S| @3| +0#4040ff13#ffffff0@59
|m+0#0000001#ffd7ff255|e|n|u| |b|a|r| @1|T| @3| +0#4040ff13#ffffff0@59
|中*0#0000001#ffd7ff255|文| +&|你*&|好| +&|C| @3| +0#4040ff13#ffffff0@59
|~| @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| |3| +0#0000000&@34

View File

@ -0,0 +1,20 @@
|f+0&#ffffff0|o@1> @71
|m+0#0000001#e0e0e08|e|n|u| |S| |f|o@1| @4| +0#4040ff13#ffffff0@59
|m+0#0000001#ffd7ff255|e|n|u| |T| |b|a|r| @4| +0#4040ff13#ffffff0@59
|中*0#0000001#ffd7ff255|文| +&|C| |你*&|好| +&@3| +0#4040ff13#ffffff0@59
|~| @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| |3| +0#0000000&@34

View File

@ -80,6 +80,7 @@ let test_values = {
\ 'complete': [['', 'w,b'], ['xxx']],
\ 'concealcursor': [['', 'n', 'nvic'], ['xxx']],
\ 'completeopt': [['', 'menu', 'menu,longest'], ['xxx', 'menu,,,longest,']],
\ 'completeitemalign': [['abbr,kind,menu'], ['xxx','abbr,menu','abbr,menu,kind,abbr', 'abbr', 'abbr1234,kind', '']],
\ 'completepopup': [['', 'height:13', 'highlight:That', 'width:10,height:234,highlight:Mine'], ['height:yes', 'width:no', 'xxx', 'xxx:99', 'border:maybe', 'border:1']],
\ 'completeslash': [['', 'slash', 'backslash'], ['xxx']],
\ 'cryptmethod': [['', 'zip'], ['xxx']],

View File

@ -1581,4 +1581,64 @@ func Test_pum_user_kind_hlgroup()
call StopVimInTerminal(buf)
endfunc
func Test_pum_completeitemalign()
CheckScreendump
let lines =<< trim END
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return {
\ 'words': [
\ { 'word': 'foo', 'kind': 'S', 'menu': 'menu' },
\ { 'word': 'bar', 'kind': 'T', 'menu': 'menu' },
\ { 'word': '你好', 'kind': 'C', 'menu': '中文' },
\]}
endfunc
set omnifunc=Omni_test
command! -nargs=0 T1 set cia=abbr,kind,menu
command! -nargs=0 T2 set cia=abbr,menu,kind
command! -nargs=0 T3 set cia=kind,abbr,menu
command! -nargs=0 T4 set cia=kind,menu,abbr
command! -nargs=0 T5 set cia=menu,abbr,kind
command! -nargs=0 T6 set cia=menu,kind,abbr
command! -nargs=0 T7 set cia&
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
call TermWait(buf)
" T1 is default
call term_sendkeys(buf, ":T1\<CR>S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_completeitemalign_01', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" T2
call term_sendkeys(buf, ":T2\<CR>S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_completeitemalign_02', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" T3
call term_sendkeys(buf, ":T3\<CR>S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_completeitemalign_03', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" T4
call term_sendkeys(buf, ":T4\<CR>S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_completeitemalign_04', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" T5
call term_sendkeys(buf, ":T5\<CR>S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_completeitemalign_05', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" T6
call term_sendkeys(buf, ":T6\<CR>S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_completeitemalign_06', {})
call term_sendkeys(buf, "\<C-E>\<Esc>:T7\<CR>")
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
754,
/**/
753,
/**/

View File

@ -2372,6 +2372,17 @@ typedef enum {
FCERR_FAILED, // error while executing the function
} funcerror_T;
/*
* Array indexes used for cp_text[].
*/
typedef enum {
CPT_ABBR, // "abbr"
CPT_KIND, // "kind"
CPT_MENU, // "menu"
CPT_INFO, // "info"
CPT_COUNT, // Number of entries
} cpitem_T;
/*
* Type for the callback function that is invoked after an option value is
* changed to validate and apply the new value.