mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.1.1123: avoid filtering autocomplete
Author: roxma <roxma@qq.com>
Problem: No way to avoid filtering for autocomplete function, causing
flickering of the popup menu.
Solution: Add the "equal" field to complete items. (closes vim/vim#3887)
73655cf0ca
closes #9566
This commit is contained in:
parent
3cd9422c4c
commit
8376d2c4b1
@ -1075,6 +1075,9 @@ items:
|
|||||||
icase when non-zero case is to be ignored when comparing
|
icase when non-zero case is to be ignored when comparing
|
||||||
items to be equal; when omitted zero is used, thus
|
items to be equal; when omitted zero is used, thus
|
||||||
items that only differ in case are added
|
items that only differ in case are added
|
||||||
|
equal when non-zero, always treat this item to be equal when
|
||||||
|
comparing. Which means, "equal=1" disables filtering
|
||||||
|
of this item.
|
||||||
dup when non-zero this match will be added even when an
|
dup when non-zero this match will be added even when an
|
||||||
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
|
||||||
@ -1082,10 +1085,10 @@ items:
|
|||||||
user_data custom data which is associated with the item and
|
user_data custom data which is associated with the item and
|
||||||
available in |v:completed_item|
|
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", "equal", "dup" and "empty" must be a string. If
|
||||||
does not meet these requirements then an error message is given and further
|
an item does not meet these requirements then an error message is given and
|
||||||
items in the list are not used. You can mix string and Dictionary items in
|
further items in the list are not used. You can mix string and Dictionary
|
||||||
the returned list.
|
items in the returned list.
|
||||||
|
|
||||||
The "menu" item is used in the popup menu and may be truncated, thus it should
|
The "menu" item is used in the popup menu and may be truncated, thus it should
|
||||||
be relatively short. The "info" item can be longer, it will be displayed in
|
be relatively short. The "info" item can be longer, it will be displayed in
|
||||||
|
@ -137,16 +137,18 @@ typedef struct compl_S compl_T;
|
|||||||
struct compl_S {
|
struct compl_S {
|
||||||
compl_T *cp_next;
|
compl_T *cp_next;
|
||||||
compl_T *cp_prev;
|
compl_T *cp_prev;
|
||||||
char_u *cp_str; /* matched text */
|
char_u *cp_str; // matched text
|
||||||
char cp_icase; /* TRUE or FALSE: ignore case */
|
char cp_icase; // TRUE or FALSE: ignore case
|
||||||
char_u *(cp_text[CPT_COUNT]); /* text for the menu */
|
char cp_equal; // TRUE or FALSE: ins_compl_equal always ok
|
||||||
char_u *cp_fname; /* file containing the match, allocated when
|
char_u *(cp_text[CPT_COUNT]); // text for the menu
|
||||||
* cp_flags has FREE_FNAME */
|
char_u *cp_fname; // file containing the match, allocated when
|
||||||
int cp_flags; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
|
// cp_flags has FREE_FNAME
|
||||||
int cp_number; /* sequence number */
|
int cp_flags; // ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME
|
||||||
|
int cp_number; // sequence number
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ORIGINAL_TEXT (1) /* the original text when the expansion begun */
|
// flags for ins_compl_add()
|
||||||
|
#define ORIGINAL_TEXT (1) // the original text when the expansion begun
|
||||||
#define FREE_FNAME (2)
|
#define FREE_FNAME (2)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2035,14 +2037,14 @@ static bool ins_compl_accept_char(int c)
|
|||||||
return vim_iswordc(c);
|
return vim_iswordc(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
|
||||||
* This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
|
// case of the originally typed text is used, and the case of the completed
|
||||||
* case of the originally typed text is used, and the case of the completed
|
// text is inferred, ie this tries to work out what case you probably wanted
|
||||||
* text is inferred, ie this tries to work out what case you probably wanted
|
// the rest of the word to be in -- webb
|
||||||
* the rest of the word to be in -- webb
|
int ins_compl_add_infercase(char_u *str_arg, int len, int icase, char_u *fname,
|
||||||
*/
|
int dir, int flags)
|
||||||
int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int dir, int flags)
|
|
||||||
{
|
{
|
||||||
|
char_u *str = str_arg;
|
||||||
int i, c;
|
int i, c;
|
||||||
int actual_len; /* Take multi-byte characters */
|
int actual_len; /* Take multi-byte characters */
|
||||||
int actual_compl_length; /* into account. */
|
int actual_compl_length; /* into account. */
|
||||||
@ -2171,10 +2173,10 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
|
|||||||
|
|
||||||
xfree(wca);
|
xfree(wca);
|
||||||
|
|
||||||
return ins_compl_add(IObuff, len, icase, fname, NULL, false, dir, flags,
|
str = IObuff;
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
return ins_compl_add(str, len, icase, fname, NULL, false, dir, flags, false);
|
return ins_compl_add(str, len, icase, fname, NULL, false, dir, flags,
|
||||||
|
false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a match to the list of matches
|
/// Add a match to the list of matches
|
||||||
@ -2191,6 +2193,7 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
|
|||||||
/// cptext itself will not be freed.
|
/// cptext itself will not be freed.
|
||||||
/// @param[in] cdir Completion direction.
|
/// @param[in] cdir Completion direction.
|
||||||
/// @param[in] adup True if duplicate matches are to be accepted.
|
/// @param[in] adup True if duplicate matches are to be accepted.
|
||||||
|
/// @param[in] equal Match is always accepted by ins_compl_equal.
|
||||||
///
|
///
|
||||||
/// @return NOTDONE if the given string is already in the list of completions,
|
/// @return NOTDONE if the given string is already in the list of completions,
|
||||||
/// otherwise it is added to the list and OK is returned. FAIL will be
|
/// otherwise it is added to the list and OK is returned. FAIL will be
|
||||||
@ -2199,7 +2202,8 @@ static int ins_compl_add(char_u *const str, int len,
|
|||||||
const bool icase, char_u *const fname,
|
const bool icase, char_u *const fname,
|
||||||
char_u *const *const cptext,
|
char_u *const *const cptext,
|
||||||
const bool cptext_allocated,
|
const bool cptext_allocated,
|
||||||
const Direction cdir, int flags, const bool adup)
|
const Direction cdir, int flags, const bool adup,
|
||||||
|
int equal)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
compl_T *match;
|
compl_T *match;
|
||||||
@ -2251,6 +2255,7 @@ static int ins_compl_add(char_u *const str, int len,
|
|||||||
match->cp_number = 0;
|
match->cp_number = 0;
|
||||||
match->cp_str = vim_strnsave(str, len);
|
match->cp_str = vim_strnsave(str, len);
|
||||||
match->cp_icase = icase;
|
match->cp_icase = icase;
|
||||||
|
match->cp_equal = equal;
|
||||||
|
|
||||||
/* match-fname is:
|
/* match-fname is:
|
||||||
* - compl_curr_match->cp_fname if it is a string equal to fname.
|
* - compl_curr_match->cp_fname if it is a string equal to fname.
|
||||||
@ -2324,6 +2329,9 @@ static int ins_compl_add(char_u *const str, int len,
|
|||||||
static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
|
static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
|
||||||
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
|
if (match->cp_equal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (match->cp_icase) {
|
if (match->cp_icase) {
|
||||||
return STRNICMP(match->cp_str, str, len) == 0;
|
return STRNICMP(match->cp_str, str, len) == 0;
|
||||||
}
|
}
|
||||||
@ -2397,7 +2405,8 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
|
|||||||
|
|
||||||
for (i = 0; i < num_matches && add_r != FAIL; i++)
|
for (i = 0; i < num_matches && add_r != FAIL; i++)
|
||||||
if ((add_r = ins_compl_add(matches[i], -1, icase,
|
if ((add_r = ins_compl_add(matches[i], -1, icase,
|
||||||
NULL, NULL, false, dir, 0, false)) == OK) {
|
NULL, NULL, false, dir, 0, false,
|
||||||
|
false)) == OK) {
|
||||||
// If dir was BACKWARD then honor it just once.
|
// If dir was BACKWARD then honor it just once.
|
||||||
dir = FORWARD;
|
dir = FORWARD;
|
||||||
}
|
}
|
||||||
@ -2466,7 +2475,7 @@ void set_completion(colnr_T startcol, list_T *list)
|
|||||||
compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
|
compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
|
||||||
compl_length);
|
compl_length);
|
||||||
if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
|
if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
|
||||||
ORIGINAL_TEXT, false) != OK) {
|
ORIGINAL_TEXT, false, false) != OK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3759,6 +3768,7 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
|
|||||||
bool icase = false;
|
bool icase = false;
|
||||||
bool adup = false;
|
bool adup = false;
|
||||||
bool aempty = false;
|
bool aempty = false;
|
||||||
|
bool aequal = false;
|
||||||
char *(cptext[CPT_COUNT]);
|
char *(cptext[CPT_COUNT]);
|
||||||
|
|
||||||
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
|
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
|
||||||
@ -3773,6 +3783,9 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
|
|||||||
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");
|
||||||
aempty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
|
aempty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
|
||||||
|
if (tv_dict_get_string(tv->vval.v_dict, (char_u *)"equal", false) != NULL) {
|
||||||
|
aequal = tv_dict_get_number(tv->vval.v_dict, (char_u *)"equal");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
word = (const char *)tv_get_string_chk(tv);
|
word = (const char *)tv_get_string_chk(tv);
|
||||||
memset(cptext, 0, sizeof(cptext));
|
memset(cptext, 0, sizeof(cptext));
|
||||||
@ -3784,7 +3797,7 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
return ins_compl_add((char_u *)word, -1, icase, NULL,
|
return ins_compl_add((char_u *)word, -1, icase, NULL,
|
||||||
(char_u **)cptext, true, dir, 0, adup);
|
(char_u **)cptext, true, dir, 0, adup, aequal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4946,7 +4959,7 @@ static int ins_complete(int c, bool enable_pum)
|
|||||||
xfree(compl_orig_text);
|
xfree(compl_orig_text);
|
||||||
compl_orig_text = vim_strnsave(line + compl_col, compl_length);
|
compl_orig_text = vim_strnsave(line + compl_col, compl_length);
|
||||||
if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
|
if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
|
||||||
ORIGINAL_TEXT, false) != OK) {
|
ORIGINAL_TEXT, false, false) != OK) {
|
||||||
xfree(compl_pattern);
|
xfree(compl_pattern);
|
||||||
compl_pattern = NULL;
|
compl_pattern = NULL;
|
||||||
xfree(compl_orig_text);
|
xfree(compl_orig_text);
|
||||||
|
@ -275,6 +275,38 @@ func Test_noinsert_complete()
|
|||||||
iunmap <F5>
|
iunmap <F5>
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_complete_no_filter()
|
||||||
|
func! s:complTest1() abort
|
||||||
|
call complete(1, [{'word': 'foobar'}])
|
||||||
|
return ''
|
||||||
|
endfunc
|
||||||
|
func! s:complTest2() abort
|
||||||
|
call complete(1, [{'word': 'foobar', 'equal': 1}])
|
||||||
|
return ''
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
let completeopt = &completeopt
|
||||||
|
|
||||||
|
" without equal=1
|
||||||
|
new
|
||||||
|
set completeopt=menuone,noinsert,menu
|
||||||
|
inoremap <F5> <C-R>=s:complTest1()<CR>
|
||||||
|
call feedkeys("i\<F5>z\<CR>\<CR>\<ESC>.", 'tx')
|
||||||
|
call assert_equal('z', getline(1))
|
||||||
|
bwipe!
|
||||||
|
|
||||||
|
" with equal=1
|
||||||
|
new
|
||||||
|
set completeopt=menuone,noinsert,menu
|
||||||
|
inoremap <F5> <C-R>=s:complTest2()<CR>
|
||||||
|
call feedkeys("i\<F5>z\<CR>\<CR>\<ESC>.", 'tx')
|
||||||
|
call assert_equal('foobar', getline(1))
|
||||||
|
bwipe!
|
||||||
|
|
||||||
|
let &completeopt = completeopt
|
||||||
|
iunmap <F5>
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_compl_vim_cmds_after_register_expr()
|
func Test_compl_vim_cmds_after_register_expr()
|
||||||
func! s:test_func()
|
func! s:test_func()
|
||||||
return 'autocmd '
|
return 'autocmd '
|
||||||
|
Loading…
Reference in New Issue
Block a user