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:
138
src/edit.c
138
src/edit.c
@@ -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.
|
||||
|
@@ -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
|
||||
|
||||
/*
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -775,6 +775,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1068,
|
||||
/**/
|
||||
1067,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user