Merge #9815 'vim-patch:8.1.1068: complete_info()'

This commit is contained in:
Justin M. Keyes
2019-03-30 21:30:16 +01:00
8 changed files with 307 additions and 18 deletions

View File

@@ -3246,7 +3246,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
r'|li_(?:next|prev|tv))\b', line)
if match:
error(filename, linenum, 'runtime/deprecated', 4,
'Accessing list_T internals directly is prohibited')
'Accessing list_T internals directly is prohibited (hint: see commit d46e37cb4c71)')
# Check for suspicious usage of "if" like
# } if (a == b) {

View File

@@ -58,9 +58,10 @@
#include "nvim/os/input.h"
#include "nvim/os/time.h"
/*
* 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
#define CTRL_X_NOT_DEFINED_YET 1
@@ -83,17 +84,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.
static char *ctrl_x_msgs[] =
{
N_(" Keyword completion (^N^P)"), /* ctrl_x_mode == 0, ^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,
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,
NULL, // CTRL_X_FINISHED
N_(" Dictionary completion (^K^N^P)"),
N_(" Thesaurus completion (^T^N^P)"),
N_(" Command-line completion (^V^N^P)"),
@@ -104,6 +106,26 @@ static char *ctrl_x_msgs[] =
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");
static char e_complwin[] = N_("E839: Completion function changed window");
static char e_compldel[] = N_("E840: Completion function deleted text");
@@ -2980,6 +3002,100 @@ bool ins_compl_active(void)
return compl_started;
}
// Get complete information
void get_complete_info(list_T *what_list, dict_T *retdict)
{
int ret = OK;
#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 (listitem_T *item = TV_LIST_ITEM_NEXT(what_list,
tv_list_first(what_list))
; item != NULL
; item = TV_LIST_ITEM_NEXT(what_list, item)) {
const char *what = tv_get_string(TV_LIST_ITEM_TV(item));
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 = tv_dict_add_str(retdict, S_LEN("mode"),
(const char *)ins_compl_mode());
}
if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) {
ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
}
if (ret == OK && (what_flag & CI_WHAT_ITEMS)) {
list_T *li = tv_list_alloc(ins_compl_len());
ret = tv_dict_add_list(retdict, S_LEN("items"), li);
if (ret == OK && compl_first_match != NULL) {
compl_T *match = compl_first_match;
do {
if (!(match->cp_flags & ORIGINAL_TEXT)) {
dict_T *di = tv_dict_alloc();
tv_list_append_dict(li, di);
tv_dict_add_str(di, S_LEN("word"),
(const char *)match->cp_str);
tv_dict_add_str(di, S_LEN("abbr"),
(const char *)match->cp_text[CPT_ABBR]);
tv_dict_add_str(di, S_LEN("menu"),
(const char *)match->cp_text[CPT_MENU]);
tv_dict_add_str(di, S_LEN("kind"),
(const char *)match->cp_text[CPT_KIND]);
tv_dict_add_str(di, S_LEN("info"),
(const char *)match->cp_text[CPT_INFO]);
tv_dict_add_str(di, S_LEN("user_data"),
(const char *)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 = tv_dict_add_nr(retdict, S_LEN("selected"),
(compl_curr_match != NULL)
? compl_curr_match->cp_number - 1 : -1);
}
// TODO(vim):
// 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

@@ -7564,6 +7564,23 @@ static void f_complete_check(typval_T *argvars, typval_T *rettv, FunPtr fptr)
RedrawingDisabled = saved;
}
// "complete_info()" function
static void f_complete_info(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
tv_dict_alloc_ret(rettv);
list_T *what_list = NULL;
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);
}
/*
* "confirm(message, buttons[, default [, type]])" function
*/

View File

@@ -64,6 +64,7 @@ return {
complete={args=2},
complete_add={args=1},
complete_check={},
complete_info={args={0, 1}},
confirm={args={1, 4}},
copy={args=1},
cos={args=1, func="float_op_wrapper", data="&cos"},

View File

@@ -712,4 +712,105 @@ func Test_popup_and_window_resize()
bwipe!
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