mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #12204 from archseer/lsp-user-data
lsp/completion: Expose completion_item under completed_items.user_data + vim-patch:8.2.0084
This commit is contained in:
commit
42b441738d
@ -1083,7 +1083,8 @@ items:
|
||||
empty when non-zero this match will be added even when it is
|
||||
an empty string
|
||||
user_data custom data which is associated with the item and
|
||||
available in |v:completed_item|
|
||||
available in |v:completed_item|; it can be any type;
|
||||
defaults to an empty string
|
||||
|
||||
All of these except "icase", "equal", "dup" and "empty" must be a string. If
|
||||
an item does not meet these requirements then an error message is given and
|
||||
|
@ -240,6 +240,13 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
|
||||
icase = 1,
|
||||
dup = 1,
|
||||
empty = 1,
|
||||
user_data = {
|
||||
nvim = {
|
||||
lsp = {
|
||||
completion_item = completion_item
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -143,6 +143,7 @@ struct compl_S {
|
||||
compl_T *cp_prev;
|
||||
char_u *cp_str; // matched text
|
||||
char_u *(cp_text[CPT_COUNT]); // text for the menu
|
||||
typval_T cp_user_data;
|
||||
char_u *cp_fname; // file containing the match, allocated when
|
||||
// cp_flags has CP_FREE_FNAME
|
||||
int cp_flags; // CP_ values
|
||||
@ -2291,7 +2292,7 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
|
||||
flags |= CP_ICASE;
|
||||
}
|
||||
|
||||
return ins_compl_add(str, len, fname, NULL, false, dir, flags, false);
|
||||
return ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false);
|
||||
}
|
||||
|
||||
/// Add a match to the list of matches
|
||||
@ -2315,6 +2316,7 @@ static int ins_compl_add(char_u *const str, int len,
|
||||
char_u *const fname,
|
||||
char_u *const *const cptext,
|
||||
const bool cptext_allocated,
|
||||
typval_T *user_data,
|
||||
const Direction cdir, int flags_arg, const bool adup)
|
||||
FUNC_ATTR_NONNULL_ARG(1)
|
||||
{
|
||||
@ -2403,6 +2405,10 @@ static int ins_compl_add(char_u *const str, int len,
|
||||
}
|
||||
}
|
||||
|
||||
if (user_data != NULL) {
|
||||
match->cp_user_data = *user_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Link the new match structure in the list of matches.
|
||||
*/
|
||||
@ -2521,7 +2527,7 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
|
||||
int dir = compl_direction;
|
||||
|
||||
for (int i = 0; i < num_matches && add_r != FAIL; i++) {
|
||||
if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, dir,
|
||||
if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
|
||||
icase ? CP_ICASE : 0, false)) == OK) {
|
||||
// If dir was BACKWARD then honor it just once.
|
||||
dir = FORWARD;
|
||||
@ -2596,7 +2602,7 @@ void set_completion(colnr_T startcol, list_T *list)
|
||||
if (p_ic) {
|
||||
flags |= CP_ICASE;
|
||||
}
|
||||
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
|
||||
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
|
||||
flags, false) != OK) {
|
||||
return;
|
||||
}
|
||||
@ -3120,6 +3126,7 @@ static void ins_compl_free(void)
|
||||
for (int i = 0; i < CPT_COUNT; i++) {
|
||||
xfree(match->cp_text[i]);
|
||||
}
|
||||
tv_clear(&match->cp_user_data);
|
||||
xfree(match);
|
||||
} while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
|
||||
compl_first_match = compl_curr_match = NULL;
|
||||
@ -3215,8 +3222,11 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
|
||||
(char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
|
||||
tv_dict_add_str(di, S_LEN("info"),
|
||||
(char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
|
||||
tv_dict_add_str(di, S_LEN("user_data"),
|
||||
(char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
|
||||
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
|
||||
tv_dict_add_str(di, S_LEN("user_data"), "");
|
||||
} else {
|
||||
tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
|
||||
}
|
||||
}
|
||||
match = match->cp_next;
|
||||
} while (match != NULL && match != compl_first_match);
|
||||
@ -3930,15 +3940,16 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
|
||||
bool empty = false;
|
||||
int flags = 0;
|
||||
char *(cptext[CPT_COUNT]);
|
||||
typval_T user_data;
|
||||
|
||||
user_data.v_type = VAR_UNKNOWN;
|
||||
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
|
||||
word = tv_dict_get_string(tv->vval.v_dict, "word", false);
|
||||
cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
|
||||
cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
|
||||
cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
|
||||
cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
|
||||
cptext[CPT_USER_DATA] = tv_dict_get_string(tv->vval.v_dict,
|
||||
"user_data", true);
|
||||
tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
|
||||
|
||||
if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
|
||||
flags |= CP_ICASE;
|
||||
@ -3960,7 +3971,7 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
|
||||
return FAIL;
|
||||
}
|
||||
return ins_compl_add((char_u *)word, -1, NULL,
|
||||
(char_u **)cptext, true, dir, flags, dup);
|
||||
(char_u **)cptext, true, &user_data, dir, flags, dup);
|
||||
}
|
||||
|
||||
// Get the next expansion(s), using "compl_pattern".
|
||||
@ -4450,9 +4461,11 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
|
||||
tv_dict_add_str(
|
||||
dict, S_LEN("info"),
|
||||
(const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
|
||||
tv_dict_add_str(
|
||||
dict, S_LEN("user_data"),
|
||||
(const char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
|
||||
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
|
||||
tv_dict_add_str(dict, S_LEN("user_data"), "");
|
||||
} else {
|
||||
tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
@ -5155,7 +5168,7 @@ static int ins_complete(int c, bool enable_pum)
|
||||
if (p_ic) {
|
||||
flags |= CP_ICASE;
|
||||
}
|
||||
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
|
||||
if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
|
||||
flags, false) != OK) {
|
||||
XFREE_CLEAR(compl_pattern);
|
||||
XFREE_CLEAR(compl_orig_text);
|
||||
|
@ -10,8 +10,7 @@
|
||||
#define CPT_MENU 1 // "menu"
|
||||
#define CPT_KIND 2 // "kind"
|
||||
#define CPT_INFO 3 // "info"
|
||||
#define CPT_USER_DATA 4 // "user data"
|
||||
#define CPT_COUNT 5 // Number of entries
|
||||
#define CPT_COUNT 4 // Number of entries
|
||||
|
||||
// values for cp_flags
|
||||
typedef enum {
|
||||
|
@ -1429,6 +1429,23 @@ dictitem_T *tv_dict_find(const dict_T *const d, const char *const key,
|
||||
return TV_DICT_HI2DI(hi);
|
||||
}
|
||||
|
||||
/// Get a typval item from a dictionary and copy it into "rettv".
|
||||
///
|
||||
/// @param[in] d Dictionary to check.
|
||||
/// @param[in] key Dictionary key.
|
||||
/// @param[in] rettv Return value.
|
||||
/// @return OK in case of success or FAIL if nothing was found.
|
||||
int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv)
|
||||
{
|
||||
dictitem_T *const di = tv_dict_find(d, key, -1);
|
||||
if (di == NULL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
tv_copy(&di->di_tv, rettv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Get a number item from a dictionary
|
||||
///
|
||||
/// Returns 0 if the entry does not exist.
|
||||
@ -1588,6 +1605,26 @@ int tv_dict_add_list(dict_T *const d, const char *const key,
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Add a typval entry to dictionary.
|
||||
///
|
||||
/// @param[out] d Dictionary to add entry to.
|
||||
/// @param[in] key Key to add.
|
||||
/// @param[in] key_len Key length.
|
||||
///
|
||||
/// @return FAIL if out of memory or key already exists.
|
||||
int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len,
|
||||
typval_T *tv)
|
||||
{
|
||||
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
|
||||
|
||||
tv_copy(tv, &item->di_tv);
|
||||
if (tv_dict_add(d, item) == FAIL) {
|
||||
tv_dict_item_free(item);
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Add a dictionary entry to dictionary
|
||||
///
|
||||
/// @param[out] d Dictionary to add entry to.
|
||||
|
@ -120,7 +120,7 @@ function! s:CompleteDone_CompleteFuncDict( findstart, base )
|
||||
\ 'menu': 'extra text',
|
||||
\ 'info': 'words are cool',
|
||||
\ 'kind': 'W',
|
||||
\ 'user_data': 'test'
|
||||
\ 'user_data': ['one', 'two']
|
||||
\ }
|
||||
\ ]
|
||||
\ }
|
||||
@ -136,7 +136,7 @@ func s:CompleteDone_CheckCompletedItemDict(pre)
|
||||
call assert_equal( 'extra text', v:completed_item[ 'menu' ] )
|
||||
call assert_equal( 'words are cool', v:completed_item[ 'info' ] )
|
||||
call assert_equal( 'W', v:completed_item[ 'kind' ] )
|
||||
call assert_equal( 'test', v:completed_item[ 'user_data' ] )
|
||||
call assert_equal( ['one', 'two'], v:completed_item[ 'user_data' ] )
|
||||
|
||||
if a:pre
|
||||
call assert_equal('function', complete_info().mode)
|
||||
@ -170,7 +170,7 @@ func Test_CompleteDoneDict()
|
||||
execute "normal a\<C-X>\<C-U>\<C-Y>"
|
||||
set completefunc&
|
||||
|
||||
call assert_equal('test', v:completed_item[ 'user_data' ])
|
||||
call assert_equal(['one', 'two'], v:completed_item[ 'user_data' ])
|
||||
call assert_true(s:called_completedone)
|
||||
|
||||
let s:called_completedone = 0
|
||||
|
@ -836,12 +836,12 @@ describe('LSP', function()
|
||||
}
|
||||
local completion_list_items = {items=completion_list}
|
||||
local expected = {
|
||||
{ abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
|
||||
{ abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
|
||||
{ abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label = 'foobar' } } } } },
|
||||
{ abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foobar', textEdit={} } } } } },
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar' } } } } },
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foobar', textEdit={} } } } } },
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', insertText='foodar', textEdit={newText='foobar'} } } } } },
|
||||
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', textEdit={newText='foobar'} } } } } },
|
||||
}
|
||||
|
||||
eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix))
|
||||
|
Loading…
Reference in New Issue
Block a user