mirror of
https://github.com/neovim/neovim.git
synced 2025-09-17 16:58:17 +00:00
vim-patch:8.0.1493: completion items cannot be annotated (#8003)
Problem: Completion items cannot be annotated.
Solution: Add a "user_data" entry to the completion item. (Ben Jackson,
coses vim/vim#2608, closes vim/vim#2508)
9b56a57cda
This commit is contained in:
@@ -1077,6 +1077,8 @@ items:
|
|||||||
item with the same word is already present.
|
item with the same word is already present.
|
||||||
empty when non-zero this match will be added even when it is
|
empty when non-zero this match will be added even when it is
|
||||||
an empty string
|
an empty string
|
||||||
|
user_data custom data which is associated with the item and
|
||||||
|
available in |v:completed_item|
|
||||||
|
|
||||||
All of these except "icase", "dup" and "empty" must be a string. If an item
|
All of these except "icase", "dup" and "empty" must be a string. If an item
|
||||||
does not meet these requirements then an error message is given and further
|
does not meet these requirements then an error message is given and further
|
||||||
@@ -1170,6 +1172,8 @@ The menu is used when:
|
|||||||
|
|
||||||
The 'pumheight' option can be used to set a maximum height. The default is to
|
The 'pumheight' option can be used to set a maximum height. The default is to
|
||||||
use all space available.
|
use all space available.
|
||||||
|
The 'pumwidth' option can be used to set a minimum width. The default is 15
|
||||||
|
characters.
|
||||||
|
|
||||||
There are three states:
|
There are three states:
|
||||||
1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P.
|
1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P.
|
||||||
|
@@ -3600,6 +3600,8 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
|
|||||||
cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", 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_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_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);
|
||||||
|
|
||||||
icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase");
|
icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase");
|
||||||
adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
|
adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
|
||||||
@@ -4043,8 +4045,9 @@ static void ins_compl_insert(int in_compl_func)
|
|||||||
// Set completed item.
|
// Set completed item.
|
||||||
// { word, abbr, menu, kind, info }
|
// { word, abbr, menu, kind, info }
|
||||||
dict_T *dict = tv_dict_alloc();
|
dict_T *dict = tv_dict_alloc();
|
||||||
tv_dict_add_str(dict, S_LEN("word"),
|
tv_dict_add_str(
|
||||||
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
|
dict, S_LEN("word"),
|
||||||
|
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
|
||||||
tv_dict_add_str(
|
tv_dict_add_str(
|
||||||
dict, S_LEN("abbr"),
|
dict, S_LEN("abbr"),
|
||||||
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
|
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
|
||||||
@@ -4057,6 +4060,9 @@ static void ins_compl_insert(int in_compl_func)
|
|||||||
tv_dict_add_str(
|
tv_dict_add_str(
|
||||||
dict, S_LEN("info"),
|
dict, S_LEN("info"),
|
||||||
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
|
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
|
||||||
|
tv_dict_add_str(
|
||||||
|
dict, S_LEN("user_data"),
|
||||||
|
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_USER_DATA]));
|
||||||
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
||||||
if (!in_compl_func) {
|
if (!in_compl_func) {
|
||||||
compl_curr_match = compl_shown_match;
|
compl_curr_match = compl_shown_match;
|
||||||
|
@@ -6,11 +6,12 @@
|
|||||||
/*
|
/*
|
||||||
* Array indexes used for cptext argument of ins_compl_add().
|
* Array indexes used for cptext argument of ins_compl_add().
|
||||||
*/
|
*/
|
||||||
#define CPT_ABBR 0 /* "abbr" */
|
#define CPT_ABBR 0 // "abbr"
|
||||||
#define CPT_MENU 1 /* "menu" */
|
#define CPT_MENU 1 // "menu"
|
||||||
#define CPT_KIND 2 /* "kind" */
|
#define CPT_KIND 2 // "kind"
|
||||||
#define CPT_INFO 3 /* "info" */
|
#define CPT_INFO 3 // "info"
|
||||||
#define CPT_COUNT 4 /* Number of entries */
|
#define CPT_USER_DATA 4 // "user data"
|
||||||
|
#define CPT_COUNT 5 // Number of entries
|
||||||
|
|
||||||
typedef int (*IndentGetter)(void);
|
typedef int (*IndentGetter)(void);
|
||||||
|
|
||||||
|
@@ -97,3 +97,123 @@ func Test_ins_complete()
|
|||||||
cd ..
|
cd ..
|
||||||
call delete('Xdir', 'rf')
|
call delete('Xdir', 'rf')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
function! s:CompleteDone_CompleteFuncDict( findstart, base )
|
||||||
|
if a:findstart
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'words': [
|
||||||
|
\ {
|
||||||
|
\ 'word': 'aword',
|
||||||
|
\ 'abbr': 'wrd',
|
||||||
|
\ 'menu': 'extra text',
|
||||||
|
\ 'info': 'words are cool',
|
||||||
|
\ 'kind': 'W',
|
||||||
|
\ 'user_data': 'test'
|
||||||
|
\ }
|
||||||
|
\ ]
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:CompleteDone_CheckCompletedItemDict()
|
||||||
|
call assert_equal( 'aword', v:completed_item[ 'word' ] )
|
||||||
|
call assert_equal( 'wrd', v:completed_item[ 'abbr' ] )
|
||||||
|
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' ] )
|
||||||
|
|
||||||
|
let s:called_completedone = 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function Test_CompleteDoneDict()
|
||||||
|
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDict()
|
||||||
|
|
||||||
|
set completefunc=<SID>CompleteDone_CompleteFuncDict
|
||||||
|
execute "normal a\<C-X>\<C-U>\<C-Y>"
|
||||||
|
set completefunc&
|
||||||
|
|
||||||
|
call assert_equal( 'test', v:completed_item[ 'user_data' ] )
|
||||||
|
call assert_true( s:called_completedone )
|
||||||
|
|
||||||
|
let s:called_completedone = 0
|
||||||
|
au! CompleteDone
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
function! s:CompleteDone_CompleteFuncDictNoUserData( findstart, base )
|
||||||
|
if a:findstart
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'words': [
|
||||||
|
\ {
|
||||||
|
\ 'word': 'aword',
|
||||||
|
\ 'abbr': 'wrd',
|
||||||
|
\ 'menu': 'extra text',
|
||||||
|
\ 'info': 'words are cool',
|
||||||
|
\ 'kind': 'W'
|
||||||
|
\ }
|
||||||
|
\ ]
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:CompleteDone_CheckCompletedItemDictNoUserData()
|
||||||
|
call assert_equal( 'aword', v:completed_item[ 'word' ] )
|
||||||
|
call assert_equal( 'wrd', v:completed_item[ 'abbr' ] )
|
||||||
|
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( '', v:completed_item[ 'user_data' ] )
|
||||||
|
|
||||||
|
let s:called_completedone = 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function Test_CompleteDoneDictNoUserData()
|
||||||
|
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemDictNoUserData()
|
||||||
|
|
||||||
|
set completefunc=<SID>CompleteDone_CompleteFuncDictNoUserData
|
||||||
|
execute "normal a\<C-X>\<C-U>\<C-Y>"
|
||||||
|
set completefunc&
|
||||||
|
|
||||||
|
call assert_equal( '', v:completed_item[ 'user_data' ] )
|
||||||
|
call assert_true( s:called_completedone )
|
||||||
|
|
||||||
|
let s:called_completedone = 0
|
||||||
|
au! CompleteDone
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
function! s:CompleteDone_CompleteFuncList( findstart, base )
|
||||||
|
if a:findstart
|
||||||
|
return 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
return [ 'aword' ]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:CompleteDone_CheckCompletedItemList()
|
||||||
|
call assert_equal( 'aword', v:completed_item[ 'word' ] )
|
||||||
|
call assert_equal( '', v:completed_item[ 'abbr' ] )
|
||||||
|
call assert_equal( '', v:completed_item[ 'menu' ] )
|
||||||
|
call assert_equal( '', v:completed_item[ 'info' ] )
|
||||||
|
call assert_equal( '', v:completed_item[ 'kind' ] )
|
||||||
|
call assert_equal( '', v:completed_item[ 'user_data' ] )
|
||||||
|
|
||||||
|
let s:called_completedone = 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function Test_CompleteDoneList()
|
||||||
|
au CompleteDone * :call <SID>CompleteDone_CheckCompletedItemList()
|
||||||
|
|
||||||
|
set completefunc=<SID>CompleteDone_CompleteFuncList
|
||||||
|
execute "normal a\<C-X>\<C-U>\<C-Y>"
|
||||||
|
set completefunc&
|
||||||
|
|
||||||
|
call assert_equal( '', v:completed_item[ 'user_data' ] )
|
||||||
|
call assert_true( s:called_completedone )
|
||||||
|
|
||||||
|
let s:called_completedone = 0
|
||||||
|
au! CompleteDone
|
||||||
|
endfunc
|
||||||
|
@@ -59,7 +59,8 @@ describe('completion', function()
|
|||||||
it('returns expected dict in normal completion', function()
|
it('returns expected dict in normal completion', function()
|
||||||
feed('ifoo<ESC>o<C-x><C-n>')
|
feed('ifoo<ESC>o<C-x><C-n>')
|
||||||
eq('foo', eval('getline(2)'))
|
eq('foo', eval('getline(2)'))
|
||||||
eq({word = 'foo', abbr = '', menu = '', info = '', kind = ''},
|
eq({word = 'foo', abbr = '', menu = '',
|
||||||
|
info = '', kind = '', user_data = ''},
|
||||||
eval('v:completed_item'))
|
eval('v:completed_item'))
|
||||||
end)
|
end)
|
||||||
it('is readonly', function()
|
it('is readonly', function()
|
||||||
@@ -84,13 +85,18 @@ describe('completion', function()
|
|||||||
feed_command('let v:completed_item.kind = "bar"')
|
feed_command('let v:completed_item.kind = "bar"')
|
||||||
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
feed_command('let v:errmsg = ""')
|
feed_command('let v:errmsg = ""')
|
||||||
|
|
||||||
|
feed_command('let v:completed_item.user_data = "bar"')
|
||||||
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
|
feed_command('let v:errmsg = ""')
|
||||||
end)
|
end)
|
||||||
it('returns expected dict in omni completion', function()
|
it('returns expected dict in omni completion', function()
|
||||||
source([[
|
source([[
|
||||||
function! TestOmni(findstart, base) abort
|
function! TestOmni(findstart, base) abort
|
||||||
return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar',
|
return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar',
|
||||||
\ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'},
|
\ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'},
|
||||||
\ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu', 'info': 'info', 'kind': 'kind'}]
|
\ {'word': 'word', 'abbr': 'abbr', 'menu': 'menu',
|
||||||
|
\ 'info': 'info', 'kind': 'kind'}]
|
||||||
endfunction
|
endfunction
|
||||||
setlocal omnifunc=TestOmni
|
setlocal omnifunc=TestOmni
|
||||||
]])
|
]])
|
||||||
@@ -107,7 +113,7 @@ describe('completion', function()
|
|||||||
{3:-- Omni completion (^O^N^P) }{4:match 1 of 2} |
|
{3:-- Omni completion (^O^N^P) }{4:match 1 of 2} |
|
||||||
]])
|
]])
|
||||||
eq({word = 'foo', abbr = 'bar', menu = 'baz',
|
eq({word = 'foo', abbr = 'bar', menu = 'baz',
|
||||||
info = 'foobar', kind = 'foobaz'},
|
info = 'foobar', kind = 'foobaz', user_data = ''},
|
||||||
eval('v:completed_item'))
|
eval('v:completed_item'))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Reference in New Issue
Block a user