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
commit a8783012e4
8 changed files with 307 additions and 18 deletions

View File

@ -2021,6 +2021,7 @@ col({expr}) Number column nr of cursor or mark
complete({startcol}, {matches}) none set Insert mode completion complete({startcol}, {matches}) none set Insert mode completion
complete_add({expr}) Number add completion match complete_add({expr}) Number add completion match
complete_check() Number check for key typed during completion complete_check() Number check for key typed during completion
complete_info([{what}]) Dict get current completion information
confirm({msg} [, {choices} [, {default} [, {type}]]]) confirm({msg} [, {choices} [, {default} [, {type}]]])
Number number of choice picked by user Number number of choice picked by user
copy({expr}) any make a shallow copy of {expr} copy({expr}) any make a shallow copy of {expr}
@ -2844,8 +2845,8 @@ cindent({lnum}) *cindent()*
See |C-indenting|. See |C-indenting|.
clearmatches() *clearmatches()* clearmatches() *clearmatches()*
Clears all matches previously defined by |matchadd()| and the Clears all matches previously defined for the current window
|:match| commands. by |matchadd()| and the |:match| commands.
*col()* *col()*
col({expr}) The result is a Number, which is the byte index of the column col({expr}) The result is a Number, which is the byte index of the column
@ -2930,6 +2931,55 @@ complete_check() *complete_check()*
Only to be used by the function specified with the Only to be used by the function specified with the
'completefunc' option. 'completefunc' option.
*complete_info()*
complete_info([{what}])
Returns a Dictionary with information about Insert mode
completion. See |ins-completion|.
The items are:
mode Current completion mode name string.
See |completion_info_mode| for the values.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
items List of completion matches. Each item is a
dictionary containing the entries "word",
"abbr", "menu", "kind", "info" and "user_data".
See |complete-items|.
selected Selected item index. First index is zero.
Index is -1 if no item is selected (showing
typed text only)
inserted Inserted string. [NOT IMPLEMENT YET]
*complete_info_mode*
mode values are:
"" Not in completion mode
"keyword" Keyword completion |i_CTRL-X_CTRL-N|
"ctrl_x" Just pressed CTRL-X |i_CTRL-X|
"whole_line" Whole lines |i_CTRL-X_CTRL-L|
"files" File names |i_CTRL-X_CTRL-F|
"tags" Tags |i_CTRL-X_CTRL-]|
"path_defines" Definition completion |i_CTRL-X_CTRL-D|
"path_patterns" Include completion |i_CTRL-X_CTRL-I|
"dictionary" Dictionary |i_CTRL-X_CTRL-K|
"thesaurus" Thesaurus |i_CTRL-X_CTRL-T|
"cmdline" Vim Command line |i_CTRL-X_CTRL-V|
"function" User defined completion |i_CTRL-X_CTRL-U|
"omni" Omni completion |i_CTRL-X_CTRL-O|
"spell" Spelling suggestions |i_CTRL-X_s|
"eval" |complete()| completion
"unknown" Other internal modes
If the optional {what} list argument is supplied, then only
the items listed in {what} are returned. Unsupported items in
{what} are silently ignored.
Examples: >
" Get all items
call complete_info()
" Get only 'mode'
call complete_info(['mode'])
" Get only 'mode' and 'pum_visible'
call complete_info(['mode', 'pum_visible'])
<
*confirm()* *confirm()*
confirm({msg} [, {choices} [, {default} [, {type}]]]) confirm({msg} [, {choices} [, {default} [, {type}]]])
Confirm() offers the user a dialog, from which a choice can be Confirm() offers the user a dialog, from which a choice can be
@ -4279,10 +4329,11 @@ getloclist({nr},[, {what}]) *getloclist()*
|getqflist()| for the supported items in {what}. |getqflist()| for the supported items in {what}.
getmatches() *getmatches()* getmatches() *getmatches()*
Returns a |List| with all matches previously defined by Returns a |List| with all matches previously defined for the
|matchadd()| and the |:match| commands. |getmatches()| is current window by |matchadd()| and the |:match| commands.
useful in combination with |setmatches()|, as |setmatches()| |getmatches()| is useful in combination with |setmatches()|,
can restore a list of matches saved by |getmatches()|. as |setmatches()| can restore a list of matches saved by
|getmatches()|.
Example: > Example: >
:echo getmatches() :echo getmatches()
< [{'group': 'MyGroup1', 'pattern': 'TODO', < [{'group': 'MyGroup1', 'pattern': 'TODO',
@ -6862,9 +6913,10 @@ setloclist({nr}, {list} [, {action}[, {what}]]) *setloclist()*
for the list of supported keys in {what}. for the list of supported keys in {what}.
setmatches({list}) *setmatches()* setmatches({list}) *setmatches()*
Restores a list of matches saved by |getmatches()|. Returns 0 Restores a list of matches saved by |getmatches() for the
if successful, otherwise -1. All current matches are cleared current window|. Returns 0 if successful, otherwise -1. All
before the list is restored. See example for |getmatches()|. current matches are cleared before the list is restored. See
example for |getmatches()|.
*setpos()* *setpos()*
setpos({expr}, {list}) setpos({expr}, {list})

View File

@ -359,8 +359,8 @@ CTRL-\ CTRL-O like CTRL-O but don't move the cursor *i_CTRL-\_CTRL-O*
CTRL-L when 'insertmode' is set: go to Normal mode *i_CTRL-L* CTRL-L when 'insertmode' is set: go to Normal mode *i_CTRL-L*
CTRL-G u break undo sequence, start new change *i_CTRL-G_u* CTRL-G u break undo sequence, start new change *i_CTRL-G_u*
CTRL-G U don't break undo with next left/right cursor *i_CTRL-G_U* CTRL-G U don't break undo with next left/right cursor *i_CTRL-G_U*
movement (but only if the cursor stays movement, if the cursor stays within
within same the line) same the line
----------------------------------------------------------------------- -----------------------------------------------------------------------
The CTRL-O command sometimes has a side effect: If the cursor was beyond the The CTRL-O command sometimes has a side effect: If the cursor was beyond the
@ -617,6 +617,7 @@ and one of the CTRL-X commands. You exit CTRL-X mode by typing a key that is
not a valid CTRL-X mode command. Valid keys are the CTRL-X command itself, not a valid CTRL-X mode command. Valid keys are the CTRL-X command itself,
CTRL-N (next), and CTRL-P (previous). CTRL-N (next), and CTRL-P (previous).
To get the current completion information, |complete_info()| can be used.
Also see the 'infercase' option if you want to adjust the case of the match. Also see the 'infercase' option if you want to adjust the case of the match.
*complete_CTRL-E* *complete_CTRL-E*

View File

@ -825,6 +825,7 @@ Insert mode completion: *completion-functions*
complete() set found matches complete() set found matches
complete_add() add to found matches complete_add() add to found matches
complete_check() check if completion should be aborted complete_check() check if completion should be aborted
complete_info() get current completion information
pumvisible() check if the popup menu is displayed pumvisible() check if the popup menu is displayed
Folding: *folding-functions* Folding: *folding-functions*

View File

@ -3246,7 +3246,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
r'|li_(?:next|prev|tv))\b', line) r'|li_(?:next|prev|tv))\b', line)
if match: if match:
error(filename, linenum, 'runtime/deprecated', 4, 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 # Check for suspicious usage of "if" like
# } if (a == b) { # } if (a == b) {

View File

@ -58,9 +58,10 @@
#include "nvim/os/input.h" #include "nvim/os/input.h"
#include "nvim/os/time.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_WANT_IDENT 0x100
#define CTRL_X_NOT_DEFINED_YET 1 #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_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) #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[] = 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)"), 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_(" Whole line completion (^L^N^P)"),
N_(" File name completion (^F^N^P)"), N_(" File name completion (^F^N^P)"),
N_(" Tag completion (^]^N^P)"), N_(" Tag completion (^]^N^P)"),
N_(" Path pattern completion (^N^P)"), N_(" Path pattern completion (^N^P)"),
N_(" Definition completion (^D^N^P)"), N_(" Definition completion (^D^N^P)"),
NULL, NULL, // CTRL_X_FINISHED
N_(" Dictionary completion (^K^N^P)"), N_(" Dictionary completion (^K^N^P)"),
N_(" Thesaurus completion (^T^N^P)"), N_(" Thesaurus completion (^T^N^P)"),
N_(" Command-line completion (^V^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. 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_hitend[] = N_("Hit end of paragraph");
static char e_complwin[] = N_("E839: Completion function changed window"); static char e_complwin[] = N_("E839: Completion function changed window");
static char e_compldel[] = N_("E840: Completion function deleted text"); static char e_compldel[] = N_("E840: Completion function deleted text");
@ -2980,6 +3002,100 @@ bool ins_compl_active(void)
return compl_started; 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 * Delete one character before the cursor and show the subset of the matches
* that match the word that is now before the cursor. * 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; 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 * "confirm(message, buttons[, default [, type]])" function
*/ */

View File

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

View File

@ -712,4 +712,105 @@ func Test_popup_and_window_resize()
bwipe! bwipe!
endfunc 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 " vim: shiftwidth=2 sts=2 expandtab