summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-03-29 12:20:27 +0100
committerBram Moolenaar <Bram@vim.org>2019-03-29 12:20:27 +0100
commitfd133323d4e1cc9c0e61c0ce357df4d36ea148e3 (patch)
treedb4227029ff088e984484404f690924f7ffa9fe1 /src
parent723d165c2fcd9f94af4e8719feda3b70c8f46868 (diff)
downloadvim-git-fd133323d4e1cc9c0e61c0ce357df4d36ea148e3.tar.gz
patch 8.1.1068: cannot get all the information about current completionv8.1.1068
Problem: Cannot get all the information about current completion. Solution: Add complete_info(). (Shougo, Hirohito Higashi, closes #4106)
Diffstat (limited to 'src')
-rw-r--r--src/edit.c138
-rw-r--r--src/evalfunc.c25
-rw-r--r--src/proto/edit.pro1
-rw-r--r--src/testdir/test_popup.vim101
-rw-r--r--src/version.c2
5 files changed, 261 insertions, 6 deletions
diff --git a/src/edit.c b/src/edit.c
index f15ee8d4c..dcead23f5 100644
--- a/src/edit.c
+++ b/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.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index c1a32f3c2..6aff4994c 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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
/*
diff --git a/src/proto/edit.pro b/src/proto/edit.pro
index 3a1573fb8..3f82bff70 100644
--- a/src/proto/edit.pro
+++ b/src/proto/edit.pro
@@ -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);
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
index 663a6a8e0..c69c3b00c 100644
--- a/src/testdir/test_popup.vim
+++ b/src/testdir/test_popup.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index b1d79b97d..ff18ac58f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -776,6 +776,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1068,
+/**/
1067,
/**/
1066,