vim-patch:9.1.0754: fixed order of items in insert-mode completion menu (#30619)

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: vim/vim#14006
closes: vim/vim#15760

6a89c94a9e
This commit is contained in:
glepnir
2024-10-03 06:45:01 +08:00
committed by GitHub
parent d3b4772ddc
commit 6a2f8958e8
11 changed files with 309 additions and 39 deletions

View File

@@ -151,13 +151,6 @@ static char *ctrl_x_mode_names[] = {
"cmdline",
};
// 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;
struct compl_S {

View File

@@ -8,3 +8,12 @@
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "insexpand.h.generated.h"
#endif
/// 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;

View File

@@ -429,6 +429,8 @@ EXTERN char *p_cms; ///< 'commentstring'
EXTERN char *p_cpt; ///< 'complete'
EXTERN OptInt p_columns; ///< 'columns'
EXTERN int p_confirm; ///< 'confirm'
EXTERN char *p_cia; ///< 'completeitemalign'
EXTERN unsigned cia_flags; ///< order flags of 'completeitemalign'
EXTERN char *p_cot; ///< 'completeopt'
EXTERN unsigned cot_flags; ///< flags from 'completeopt'
// Keep in sync with p_cot_values in optionstr.c

View File

@@ -1426,6 +1426,26 @@ return {
type = 'string',
varname = 'p_cfu',
},
{
abbreviation = 'cia',
cb = 'did_set_completeitemalign',
defaults = { if_true = 'abbr,kind,menu' },
deny_duplicates = true,
desc = [=[
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.
]=],
full_name = 'completeitemalign',
list = 'onecomma',
scope = { 'global' },
short_desc = N_('Insert mode completion item align order'),
type = 'string',
varname = 'p_cia',
},
{
abbreviation = 'cot',
cb = 'did_set_completeopt',

View File

@@ -995,6 +995,51 @@ int expand_set_complete(optexpand_T *args, int *numMatches, char ***matches)
matches);
}
/// The 'completeitemalign' option is changed.
const char *did_set_completeitemalign(optset_T *args)
{
char *p = p_cia;
unsigned new_cia_flags = 0;
bool seen[3] = { false, false, false };
int count = 0;
char buf[10];
while (*p) {
copy_option_part(&p, buf, sizeof(buf), ",");
if (count >= 3) {
return e_invarg;
}
if (strequal(buf, "abbr")) {
if (seen[CPT_ABBR]) {
return e_invarg;
}
new_cia_flags = new_cia_flags * 10 + CPT_ABBR;
seen[CPT_ABBR] = true;
count++;
} else if (strequal(buf, "kind")) {
if (seen[CPT_KIND]) {
return e_invarg;
}
new_cia_flags = new_cia_flags * 10 + CPT_KIND;
seen[CPT_KIND] = true;
count++;
} else if (strequal(buf, "menu")) {
if (seen[CPT_MENU]) {
return e_invarg;
}
new_cia_flags = new_cia_flags * 10 + CPT_MENU;
seen[CPT_MENU] = true;
count++;
} else {
return e_invarg;
}
}
if (new_cia_flags == 0 || count != 3) {
return e_invarg;
}
cia_flags = new_cia_flags;
return NULL;
}
/// The 'completeopt' option is changed.
const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED)
{

View File

@@ -525,6 +525,27 @@ static void pum_grid_puts_with_attrs(int col, int cells, const char *text, int t
}
}
static inline void pum_align_order(int *order)
{
bool 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 *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".
void pum_redraw(void)
{
@@ -621,34 +642,27 @@ void pum_redraw(void)
}
// 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
int grid_col = col_off;
int totwidth = 0;
for (int round = 0; round < 3; round++) {
hlf = hlfs[round];
int order[3];
int items_width_array[3] = { pum_base_width, pum_kind_width, pum_extra_width };
pum_align_order(order);
int basic_width = items_width_array[order[0]]; // first item width
bool last_isabbr = order[2] == CPT_ABBR;
for (int j = 0; j < 3; j++) {
int item_type = order[j];
hlf = hlfs[item_type];
attr = win_hl_attr(curwin, (int)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);
}
int width = 0;
char *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)) {
if (s == NULL) {
@@ -737,31 +751,31 @@ void pum_redraw(void)
}
}
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;
}
bool next_isempty = false;
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;
}
if (pum_rl) {
grid_line_fill(col_off - pum_base_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr);
grid_col = col_off - pum_base_width - n;
grid_line_fill(col_off - basic_width - n + 1, grid_col + 1, schar_from_ascii(' '), attr);
grid_col = col_off - basic_width - n;
} else {
grid_line_fill(grid_col, col_off + pum_base_width + n, schar_from_ascii(' '), attr);
grid_col = col_off + pum_base_width + n;
grid_line_fill(grid_col, col_off + basic_width + n, schar_from_ascii(' '), attr);
grid_col = col_off + basic_width + n;
}
totwidth = pum_base_width + n;
totwidth = basic_width + n;
}
if (pum_rl) {