0
0
mirror of https://github.com/vim/vim.git synced 2025-10-13 06:54:15 -04:00

patch 8.1.1068: cannot get all the information about current completion

Problem:    Cannot get all the information about current completion.
Solution:   Add complete_info(). (Shougo, Hirohito Higashi, closes #4106)
This commit is contained in:
Bram Moolenaar
2019-03-29 12:20:27 +01:00
parent 723d165c2f
commit fd133323d4
8 changed files with 328 additions and 19 deletions

View File

@@ -15,7 +15,9 @@
#ifdef FEAT_INS_EXPAND
/*
* definitions used for CTRL-X submode
* Definitions used for CTRL-X submode.
* Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[] and
* ctrl_x_mode_names[].
*/
# define CTRL_X_WANT_IDENT 0x100
@@ -40,18 +42,18 @@
# define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
# define CTRL_X_MODE_LINE_OR_EVAL(m) ((m) == CTRL_X_WHOLE_LINE || (m) == CTRL_X_EVAL)
/* Message for CTRL-X mode, index is ctrl_x_mode. */
// Message for CTRL-X mode, index is ctrl_x_mode.
static char *ctrl_x_msgs[] =
{
N_(" Keyword completion (^N^P)"), /* CTRL_X_NORMAL, ^P/^N compl. */
N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
NULL, /* CTRL_X_SCROLL: depends on state */
NULL, // CTRL_X_SCROLL: depends on state
N_(" Whole line completion (^L^N^P)"),
N_(" File name completion (^F^N^P)"),
N_(" Tag completion (^]^N^P)"),
N_(" Path pattern completion (^N^P)"),
N_(" Definition completion (^D^N^P)"),
NULL, /* CTRL_X_FINISHED */
NULL, // CTRL_X_FINISHED
N_(" Dictionary completion (^K^N^P)"),
N_(" Thesaurus completion (^T^N^P)"),
N_(" Command-line completion (^V^N^P)"),
@@ -59,9 +61,30 @@ static char *ctrl_x_msgs[] =
N_(" Omni completion (^O^N^P)"),
N_(" Spelling suggestion (s^N^P)"),
N_(" Keyword Local completion (^N^P)"),
NULL, /* CTRL_X_EVAL doesn't use msg. */
NULL, // CTRL_X_EVAL doesn't use msg.
};
static char *ctrl_x_mode_names[] = {
"keyword",
"ctrl_x",
"unknown", // CTRL_X_SCROLL
"whole_line",
"files",
"tags",
"path_patterns",
"path_defines",
"unknown", // CTRL_X_FINISHED
"dictionary",
"thesaurus",
"cmdline",
"function",
"omni",
"spell",
NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
"eval"
};
static char e_hitend[] = N_("Hit end of paragraph");
# ifdef FEAT_COMPL_FUNC
static char e_complwin[] = N_("E839: Completion function changed window");
@@ -163,6 +186,7 @@ static void ins_compl_files(int count, char_u **files, int thesaurus, int flags,
static char_u *find_line_end(char_u *ptr);
static void ins_compl_free(void);
static void ins_compl_clear(void);
static char_u *ins_compl_mode(void);
static int ins_compl_bs(void);
static int ins_compl_need_restart(void);
static void ins_compl_new_leader(void);
@@ -3525,6 +3549,108 @@ ins_compl_active(void)
return compl_started;
}
/*
* Get complete information
*/
void
get_complete_info(list_T *what_list, dict_T *retdict)
{
int ret = OK;
listitem_T *item;
#define CI_WHAT_MODE 0x01
#define CI_WHAT_PUM_VISIBLE 0x02
#define CI_WHAT_ITEMS 0x04
#define CI_WHAT_SELECTED 0x08
#define CI_WHAT_INSERTED 0x10
#define CI_WHAT_ALL 0xff
int what_flag;
if (what_list == NULL)
what_flag = CI_WHAT_ALL;
else
{
what_flag = 0;
for (item = what_list->lv_first; item != NULL; item = item->li_next)
{
char_u *what = tv_get_string(&item->li_tv);
if (STRCMP(what, "mode") == 0)
what_flag |= CI_WHAT_MODE;
else if (STRCMP(what, "pum_visible") == 0)
what_flag |= CI_WHAT_PUM_VISIBLE;
else if (STRCMP(what, "items") == 0)
what_flag |= CI_WHAT_ITEMS;
else if (STRCMP(what, "selected") == 0)
what_flag |= CI_WHAT_SELECTED;
else if (STRCMP(what, "inserted") == 0)
what_flag |= CI_WHAT_INSERTED;
}
}
if (ret == OK && (what_flag & CI_WHAT_MODE))
ret = dict_add_string(retdict, "mode", ins_compl_mode());
if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE))
ret = dict_add_number(retdict, "pum_visible", pum_visible());
if (ret == OK && (what_flag & CI_WHAT_ITEMS))
{
list_T *li;
dict_T *di;
compl_T *match;
li = list_alloc();
if (li == NULL)
return;
ret = dict_add_list(retdict, "items", li);
if (ret == OK && compl_first_match != NULL)
{
match = compl_first_match;
do
{
if (!(match->cp_flags & ORIGINAL_TEXT))
{
di = dict_alloc();
if (di == NULL)
return;
ret = list_append_dict(li, di);
if (ret != OK)
return;
dict_add_string(di, "word", match->cp_str);
dict_add_string(di, "abbr", match->cp_text[CPT_ABBR]);
dict_add_string(di, "menu", match->cp_text[CPT_MENU]);
dict_add_string(di, "kind", match->cp_text[CPT_KIND]);
dict_add_string(di, "info", match->cp_text[CPT_INFO]);
dict_add_string(di, "user_data",
match->cp_text[CPT_USER_DATA]);
}
match = match->cp_next;
}
while (match != NULL && match != compl_first_match);
}
}
if (ret == OK && (what_flag & CI_WHAT_SELECTED))
ret = dict_add_number(retdict, "selected", (compl_curr_match != NULL) ?
compl_curr_match->cp_number - 1 : -1);
// TODO
// if (ret == OK && (what_flag & CI_WHAT_INSERTED))
}
/*
* Return Insert completion mode name string
*/
static char_u *
ins_compl_mode(void)
{
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || compl_started)
return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
return (char_u *)"";
}
/*
* Delete one character before the cursor and show the subset of the matches
* that match the word that is now before the cursor.

View File

@@ -113,6 +113,7 @@ static void f_col(typval_T *argvars, typval_T *rettv);
static void f_complete(typval_T *argvars, typval_T *rettv);
static void f_complete_add(typval_T *argvars, typval_T *rettv);
static void f_complete_check(typval_T *argvars, typval_T *rettv);
static void f_complete_info(typval_T *argvars, typval_T *rettv);
#endif
static void f_confirm(typval_T *argvars, typval_T *rettv);
static void f_copy(typval_T *argvars, typval_T *rettv);
@@ -593,6 +594,7 @@ static struct fst
{"complete", 2, 2, f_complete},
{"complete_add", 1, 1, f_complete_add},
{"complete_check", 0, 0, f_complete_check},
{"complete_info", 0, 1, f_complete_info},
#endif
{"confirm", 1, 4, f_confirm},
{"copy", 1, 1, f_copy},
@@ -2600,6 +2602,29 @@ f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = compl_interrupted;
RedrawingDisabled = saved;
}
/*
* "complete_info()" function
*/
static void
f_complete_info(typval_T *argvars, typval_T *rettv)
{
list_T *what_list = NULL;
if (rettv_dict_alloc(rettv) != OK)
return;
if (argvars[0].v_type != VAR_UNKNOWN)
{
if (argvars[0].v_type != VAR_LIST)
{
emsg(_(e_listreq));
return;
}
what_list = argvars[0].vval.v_list;
}
get_complete_info(what_list, rettv->vval.v_dict);
}
#endif
/*

View File

@@ -18,6 +18,7 @@ void ins_compl_show_pum(void);
char_u *find_word_start(char_u *ptr);
char_u *find_word_end(char_u *ptr);
int ins_compl_active(void);
void get_complete_info(list_T *what_list, dict_T *retdict);
int ins_compl_add_tv(typval_T *tv, int dir);
void ins_compl_check_keys(int frequency, int in_compl_func);
int get_literal(void);

View File

@@ -896,4 +896,105 @@ func Test_menu_only_exists_in_terminal()
endtry
endfunc
func Test_popup_complete_info_01()
new
inoremap <buffer><F5> <C-R>=complete_info().mode<CR>
func s:complTestEval() abort
call complete(1, ['aa', 'ab'])
return ''
endfunc
inoremap <buffer><F6> <C-R>=s:complTestEval()<CR>
call writefile([
\ 'dummy dummy.txt 1',
\], 'Xdummy.txt')
setlocal tags=Xdummy.txt
setlocal dictionary=Xdummy.txt
setlocal thesaurus=Xdummy.txt
setlocal omnifunc=syntaxcomplete#Complete
setlocal completefunc=syntaxcomplete#Complete
setlocal spell
for [keys, mode_name] in [
\ ["", ''],
\ ["\<C-X>", 'ctrl_x'],
\ ["\<C-X>\<C-N>", 'keyword'],
\ ["\<C-X>\<C-P>", 'keyword'],
\ ["\<C-X>\<C-L>", 'whole_line'],
\ ["\<C-X>\<C-F>", 'files'],
\ ["\<C-X>\<C-]>", 'tags'],
\ ["\<C-X>\<C-D>", 'path_defines'],
\ ["\<C-X>\<C-I>", 'path_patterns'],
\ ["\<C-X>\<C-K>", 'dictionary'],
\ ["\<C-X>\<C-T>", 'thesaurus'],
\ ["\<C-X>\<C-V>", 'cmdline'],
\ ["\<C-X>\<C-U>", 'function'],
\ ["\<C-X>\<C-O>", 'omni'],
\ ["\<C-X>s", 'spell'],
\ ["\<F6>", 'eval'],
\]
call feedkeys("i" . keys . "\<F5>\<Esc>", 'tx')
call assert_equal(mode_name, getline('.'))
%d
endfor
call delete('Xdummy.txt')
bwipe!
endfunc
func UserDefinedComplete(findstart, base)
if a:findstart
return 0
else
return [
\ { 'word': 'Jan', 'menu': 'January' },
\ { 'word': 'Feb', 'menu': 'February' },
\ { 'word': 'Mar', 'menu': 'March' },
\ { 'word': 'Apr', 'menu': 'April' },
\ { 'word': 'May', 'menu': 'May' },
\ ]
endif
endfunc
func GetCompleteInfo()
if empty(g:compl_what)
let g:compl_info = complete_info()
else
let g:compl_info = complete_info(g:compl_what)
endif
return ''
endfunc
func Test_popup_complete_info_02()
new
inoremap <buffer><F5> <C-R>=GetCompleteInfo()<CR>
setlocal completefunc=UserDefinedComplete
let d = {
\ 'mode': 'function',
\ 'pum_visible': 1,
\ 'items': [
\ {'word': 'Jan', 'menu': 'January', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
\ {'word': 'Feb', 'menu': 'February', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
\ {'word': 'Mar', 'menu': 'March', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
\ {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
\ {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}
\ ],
\ 'selected': 0,
\ }
let g:compl_what = []
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info)
let g:compl_what = ['mode', 'pum_visible', 'selected']
call remove(d, 'items')
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info)
let g:compl_what = ['mode']
call remove(d, 'selected')
call remove(d, 'pum_visible')
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info)
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

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