Mercurial > vim
changeset 36228:11bd7f8182fd v9.1.0754
patch 9.1.0754: fixed order of items in insert-mode completion menu
Commit: https://github.com/vim/vim/commit/6a89c94a9eeee53481ced1a1260a177bffde4c0f
Author: glepnir <glephunter@gmail.com>
Date: Tue Oct 1 20:32:12 2024 +0200
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>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 01 Oct 2024 20:45:03 +0200 |
parents | 8bfde9d1f48e |
children | 36fd920e89bb |
files | runtime/doc/options.txt runtime/doc/tags runtime/doc/version9.txt runtime/optwin.vim src/insexpand.c src/option.h src/optiondefs.h src/optionstr.c src/popupmenu.c src/proto/optionstr.pro src/testdir/dumps/Test_pum_completeitemalign_01.dump src/testdir/dumps/Test_pum_completeitemalign_02.dump src/testdir/dumps/Test_pum_completeitemalign_03.dump src/testdir/dumps/Test_pum_completeitemalign_04.dump src/testdir/dumps/Test_pum_completeitemalign_05.dump src/testdir/dumps/Test_pum_completeitemalign_06.dump src/testdir/gen_opt_test.vim src/testdir/test_popup.vim src/version.c src/vim.h |
diffstat | 20 files changed, 326 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -2102,6 +2102,16 @@ A jump table for the options with a shor 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|
--- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -134,6 +134,7 @@ '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 @@ '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'*
--- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -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)
--- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -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)
--- a/src/insexpand.c +++ b/src/insexpand.c @@ -88,15 +88,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. */ typedef struct compl_S compl_T; @@ -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];
--- a/src/option.h +++ b/src/option.h @@ -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
--- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -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}
--- a/src/optionstr.c +++ b/src/optionstr.c @@ -1635,6 +1635,58 @@ expand_set_completeopt(optexpand_T *args 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.
--- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -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
--- a/src/proto/optionstr.pro +++ b/src/proto/optionstr.pro @@ -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);
new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_pum_completeitemalign_01.dump @@ -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
new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_pum_completeitemalign_02.dump @@ -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
new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_pum_completeitemalign_03.dump @@ -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
new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_pum_completeitemalign_04.dump @@ -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
new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_pum_completeitemalign_05.dump @@ -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
new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_pum_completeitemalign_06.dump @@ -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
--- a/src/testdir/gen_opt_test.vim +++ b/src/testdir/gen_opt_test.vim @@ -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']],
--- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -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
--- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 754, +/**/ 753, /**/ 752,
--- a/src/vim.h +++ b/src/vim.h @@ -2373,6 +2373,17 @@ typedef enum { } 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. *