mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
completion: Add v:completed_item feature #2563
Reviewed-by: Michael Reed <m.reed@mykolab.com> Reviewed-by: Luke Andrew <luke.github@la.id.au> Reviewed-by: Justin M. Keyes <justinkz@gmail.com> Reviewed-by: Florian Walch <florian@fwalch.com>
This commit is contained in:
parent
8ef5a61dd6
commit
d9f97e3026
@ -506,6 +506,8 @@ ColorScheme After loading a color scheme. |:colorscheme|
|
|||||||
CompleteDone After Insert mode completion is done. Either
|
CompleteDone After Insert mode completion is done. Either
|
||||||
when something was completed or abandoning
|
when something was completed or abandoning
|
||||||
completion. |ins-completion|
|
completion. |ins-completion|
|
||||||
|
The |v:completed_item| variable contains the
|
||||||
|
completed item.
|
||||||
|
|
||||||
*CursorHold*
|
*CursorHold*
|
||||||
CursorHold When the user doesn't press a key for the time
|
CursorHold When the user doesn't press a key for the time
|
||||||
|
@ -1326,6 +1326,12 @@ v:cmdbang Set like v:cmdarg for a file read/write command. When a "!"
|
|||||||
can only be used in autocommands. For user commands |<bang>|
|
can only be used in autocommands. For user commands |<bang>|
|
||||||
can be used.
|
can be used.
|
||||||
|
|
||||||
|
*v:completed_item* *completed_item-variable*
|
||||||
|
v:completed_item
|
||||||
|
Dictionary containing the most recent |complete-items| after
|
||||||
|
|CompleteDone|. Empty if the completion failed, or after
|
||||||
|
leaving and re-entering insert mode.
|
||||||
|
|
||||||
*v:count* *count-variable*
|
*v:count* *count-variable*
|
||||||
v:count The count given for the last Normal mode command. Can be used
|
v:count The count given for the last Normal mode command. Can be used
|
||||||
to get the count before a mapping. Read-only. Example: >
|
to get the count before a mapping. Read-only. Example: >
|
||||||
|
@ -2734,6 +2734,8 @@ static void ins_compl_clear(void)
|
|||||||
xfree(compl_orig_text);
|
xfree(compl_orig_text);
|
||||||
compl_orig_text = NULL;
|
compl_orig_text = NULL;
|
||||||
compl_enter_selects = FALSE;
|
compl_enter_selects = FALSE;
|
||||||
|
// clear v:completed_item
|
||||||
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3815,6 +3817,8 @@ static void ins_compl_delete(void)
|
|||||||
// TODO: is this sufficient for redrawing? Redrawing everything causes
|
// TODO: is this sufficient for redrawing? Redrawing everything causes
|
||||||
// flicker, thus we can't do that.
|
// flicker, thus we can't do that.
|
||||||
changed_cline_bef_curs();
|
changed_cline_bef_curs();
|
||||||
|
// clear v:completed_item
|
||||||
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Insert the new text being completed. */
|
/* Insert the new text being completed. */
|
||||||
@ -3825,6 +3829,21 @@ static void ins_compl_insert(void)
|
|||||||
compl_used_match = FALSE;
|
compl_used_match = FALSE;
|
||||||
else
|
else
|
||||||
compl_used_match = TRUE;
|
compl_used_match = TRUE;
|
||||||
|
|
||||||
|
// Set completed item.
|
||||||
|
// { word, abbr, menu, kind, info }
|
||||||
|
dict_T *dict = dict_alloc();
|
||||||
|
dict_add_nr_str(dict, "word", 0L,
|
||||||
|
EMPTY_IF_NULL(compl_shown_match->cp_str));
|
||||||
|
dict_add_nr_str(dict, "abbr", 0L,
|
||||||
|
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
|
||||||
|
dict_add_nr_str(dict, "menu", 0L,
|
||||||
|
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_MENU]));
|
||||||
|
dict_add_nr_str(dict, "kind", 0L,
|
||||||
|
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_KIND]));
|
||||||
|
dict_add_nr_str(dict, "info", 0L,
|
||||||
|
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
|
||||||
|
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -426,7 +426,8 @@ static struct vimvar {
|
|||||||
{VV_NAME("oldfiles", VAR_LIST), 0},
|
{VV_NAME("oldfiles", VAR_LIST), 0},
|
||||||
{VV_NAME("windowid", VAR_NUMBER), VV_RO},
|
{VV_NAME("windowid", VAR_NUMBER), VV_RO},
|
||||||
{VV_NAME("progpath", VAR_STRING), VV_RO},
|
{VV_NAME("progpath", VAR_STRING), VV_RO},
|
||||||
{VV_NAME("command_output", VAR_STRING), 0}
|
{VV_NAME("command_output", VAR_STRING), 0},
|
||||||
|
{VV_NAME("completed_item", VAR_DICT), VV_RO},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* shorthand */
|
/* shorthand */
|
||||||
@ -435,6 +436,7 @@ static struct vimvar {
|
|||||||
#define vv_float vv_di.di_tv.vval.v_float
|
#define vv_float vv_di.di_tv.vval.v_float
|
||||||
#define vv_str vv_di.di_tv.vval.v_string
|
#define vv_str vv_di.di_tv.vval.v_string
|
||||||
#define vv_list vv_di.di_tv.vval.v_list
|
#define vv_list vv_di.di_tv.vval.v_list
|
||||||
|
#define vv_dict vv_di.di_tv.vval.v_dict
|
||||||
#define vv_tv vv_di.di_tv
|
#define vv_tv vv_di.di_tv
|
||||||
|
|
||||||
static dictitem_T vimvars_var; /* variable used for v: */
|
static dictitem_T vimvars_var; /* variable used for v: */
|
||||||
@ -16281,7 +16283,7 @@ void set_vim_var_nr(int idx, long val)
|
|||||||
/*
|
/*
|
||||||
* Get number v: variable value.
|
* Get number v: variable value.
|
||||||
*/
|
*/
|
||||||
long get_vim_var_nr(int idx)
|
long get_vim_var_nr(int idx) FUNC_ATTR_PURE
|
||||||
{
|
{
|
||||||
return vimvars[idx].vv_nr;
|
return vimvars[idx].vv_nr;
|
||||||
}
|
}
|
||||||
@ -16289,7 +16291,7 @@ long get_vim_var_nr(int idx)
|
|||||||
/*
|
/*
|
||||||
* Get string v: variable value. Uses a static buffer, can only be used once.
|
* Get string v: variable value. Uses a static buffer, can only be used once.
|
||||||
*/
|
*/
|
||||||
char_u *get_vim_var_str(int idx) FUNC_ATTR_NONNULL_RET
|
char_u *get_vim_var_str(int idx) FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
return get_tv_string(&vimvars[idx].vv_tv);
|
return get_tv_string(&vimvars[idx].vv_tv);
|
||||||
}
|
}
|
||||||
@ -16298,11 +16300,18 @@ char_u *get_vim_var_str(int idx) FUNC_ATTR_NONNULL_RET
|
|||||||
* Get List v: variable value. Caller must take care of reference count when
|
* Get List v: variable value. Caller must take care of reference count when
|
||||||
* needed.
|
* needed.
|
||||||
*/
|
*/
|
||||||
list_T *get_vim_var_list(int idx)
|
list_T *get_vim_var_list(int idx) FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
return vimvars[idx].vv_list;
|
return vimvars[idx].vv_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get Dictionary v: variable value. Caller must take care of reference count
|
||||||
|
/// when needed.
|
||||||
|
dict_T *get_vim_var_dict(int idx) FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
|
||||||
|
{
|
||||||
|
return vimvars[idx].vv_dict;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set v:char to character "c".
|
* Set v:char to character "c".
|
||||||
*/
|
*/
|
||||||
@ -16334,8 +16343,7 @@ void set_vcount(long count, long count1, int set_prevcount)
|
|||||||
/*
|
/*
|
||||||
* Set string v: variable to a copy of "val".
|
* Set string v: variable to a copy of "val".
|
||||||
*/
|
*/
|
||||||
void
|
void set_vim_var_string (
|
||||||
set_vim_var_string (
|
|
||||||
int idx,
|
int idx,
|
||||||
char_u *val,
|
char_u *val,
|
||||||
int len /* length of "val" to use or -1 (whole string) */
|
int len /* length of "val" to use or -1 (whole string) */
|
||||||
@ -16365,6 +16373,26 @@ void set_vim_var_list(int idx, list_T *val)
|
|||||||
++val->lv_refcount;
|
++val->lv_refcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set Dictionary v: variable to "val".
|
||||||
|
void set_vim_var_dict(int idx, dict_T *val) FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
dict_unref(vimvars[idx].vv_dict);
|
||||||
|
|
||||||
|
// Set readonly
|
||||||
|
int todo = (int)val->dv_hashtab.ht_used;
|
||||||
|
for (hashitem_T *hi = val->dv_hashtab.ht_array; todo > 0 ; ++hi) {
|
||||||
|
if (HASHITEM_EMPTY(hi)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
--todo;
|
||||||
|
HI2DI(hi)->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
vimvars[idx].vv_dict = val;
|
||||||
|
++val->dv_refcount;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set v:register if needed.
|
* Set v:register if needed.
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +64,7 @@ enum {
|
|||||||
VV_WINDOWID,
|
VV_WINDOWID,
|
||||||
VV_PROGPATH,
|
VV_PROGPATH,
|
||||||
VV_COMMAND_OUTPUT,
|
VV_COMMAND_OUTPUT,
|
||||||
|
VV_COMPLETED_ITEM,
|
||||||
VV_LEN, /* number of v: vars */
|
VV_LEN, /* number of v: vars */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,6 +63,9 @@
|
|||||||
# define ASCII_ISALPHA(c) (ASCII_ISUPPER(c) || ASCII_ISLOWER(c))
|
# define ASCII_ISALPHA(c) (ASCII_ISUPPER(c) || ASCII_ISLOWER(c))
|
||||||
# define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || ascii_isdigit(c))
|
# define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || ascii_isdigit(c))
|
||||||
|
|
||||||
|
/* Returns empty string if it is NULL. */
|
||||||
|
#define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"")
|
||||||
|
|
||||||
/* macro version of chartab().
|
/* macro version of chartab().
|
||||||
* Only works with values 0-255!
|
* Only works with values 0-255!
|
||||||
* Doesn't work for UTF-8 mode with chars >= 0x80. */
|
* Doesn't work for UTF-8 mode with chars >= 0x80. */
|
||||||
|
56
test/functional/viml/completion_spec.lua
Normal file
56
test/functional/viml/completion_spec.lua
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
local helpers = require('test.functional.helpers')
|
||||||
|
local clear, feed, execute = helpers.clear, helpers.feed, helpers.execute
|
||||||
|
local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
|
||||||
|
local execute, source = helpers.execute, helpers.source
|
||||||
|
|
||||||
|
describe("completion", function()
|
||||||
|
before_each(function()
|
||||||
|
clear()
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("v:completed_item", function()
|
||||||
|
it('returns expected dict in normal completion', function()
|
||||||
|
feed('ifoo<ESC>o<C-x><C-n><ESC>')
|
||||||
|
eq('foo', eval('getline(2)'))
|
||||||
|
eq({word = 'foo', abbr = '', menu = '', info = '', kind = ''},
|
||||||
|
eval('v:completed_item'))
|
||||||
|
end)
|
||||||
|
it('is readonly', function()
|
||||||
|
feed('ifoo<ESC>o<C-x><C-n><ESC>')
|
||||||
|
|
||||||
|
execute('let v:completed_item.word = "bar"')
|
||||||
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
|
execute('let v:errmsg = ""')
|
||||||
|
|
||||||
|
execute('let v:completed_item.abbr = "bar"')
|
||||||
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
|
execute('let v:errmsg = ""')
|
||||||
|
|
||||||
|
execute('let v:completed_item.menu = "bar"')
|
||||||
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
|
execute('let v:errmsg = ""')
|
||||||
|
|
||||||
|
execute('let v:completed_item.info = "bar"')
|
||||||
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
|
execute('let v:errmsg = ""')
|
||||||
|
|
||||||
|
execute('let v:completed_item.kind = "bar"')
|
||||||
|
neq(nil, string.find(eval('v:errmsg'), '^E46: '))
|
||||||
|
execute('let v:errmsg = ""')
|
||||||
|
end)
|
||||||
|
it('returns expected dict in omni completion', function()
|
||||||
|
source([[
|
||||||
|
function! TestOmni(findstart, base) abort
|
||||||
|
return a:findstart ? 0 : [{'word': 'foo', 'abbr': 'bar',
|
||||||
|
\ 'menu': 'baz', 'info': 'foobar', 'kind': 'foobaz'}]
|
||||||
|
endfunction
|
||||||
|
setlocal omnifunc=TestOmni
|
||||||
|
]])
|
||||||
|
feed('i<C-x><C-o><ESC>')
|
||||||
|
eq('foo', eval('getline(1)'))
|
||||||
|
eq({word = 'foo', abbr = 'bar', menu = 'baz',
|
||||||
|
info = 'foobar', kind = 'foobaz'},
|
||||||
|
eval('v:completed_item'))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue
Block a user