mirror of
https://github.com/neovim/neovim.git
synced 2025-12-11 17:12:40 +00:00
Merge pull request #19936 from zeertzjq/vim-8.2.3989
vim-patch:8.2.{2534,3989,4037}: Insert mode completion tests and fixes
This commit is contained in:
@@ -659,17 +659,23 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
|
|||||||
|
|
||||||
/// Add a match to the list of matches
|
/// Add a match to the list of matches
|
||||||
///
|
///
|
||||||
/// @param[in] str Match to add.
|
/// @param[in] str text of the match to add
|
||||||
/// @param[in] len Match length, -1 to use #STRLEN.
|
/// @param[in] len length of "str". If -1, then the length of "str" is computed.
|
||||||
/// @param[in] fname File name match comes from. May be NULL.
|
/// @param[in] fname file name to associate with this match. May be NULL.
|
||||||
/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
|
/// @param[in] cptext list of strings to use with this match (for abbr, menu, info
|
||||||
/// must have exactly #CPT_COUNT items.
|
/// and kind). May be NULL.
|
||||||
|
/// If not NULL, must have exactly #CPT_COUNT items.
|
||||||
/// @param[in] cptext_allocated If true, will not copy cptext strings.
|
/// @param[in] cptext_allocated If true, will not copy cptext strings.
|
||||||
///
|
///
|
||||||
/// @note Will free strings in case of error.
|
/// @note Will free strings in case of error.
|
||||||
/// cptext itself will not be freed.
|
/// cptext itself will not be freed.
|
||||||
/// @param[in] cdir Completion direction.
|
/// @param[in] user_data user supplied data (any vim type) for this match
|
||||||
/// @param[in] adup True if duplicate matches are to be accepted.
|
/// @param[in] cdir match direction. If 0, use "compl_direction".
|
||||||
|
/// @param[in] flags_arg match flags (cp_flags)
|
||||||
|
/// @param[in] adup accept this match even if it is already present.
|
||||||
|
///
|
||||||
|
/// If "cdir" is FORWARD, then the match is added after the current match.
|
||||||
|
/// Otherwise, it is added before the current match.
|
||||||
///
|
///
|
||||||
/// @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
|
||||||
@@ -768,7 +774,8 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname,
|
|||||||
match->cp_user_data = *user_data;
|
match->cp_user_data = *user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link the new match structure in the list of matches.
|
// Link the new match structure after (FORWARD) or before (BACKWARD) the
|
||||||
|
// current match in the list of matches .
|
||||||
if (compl_first_match == NULL) {
|
if (compl_first_match == NULL) {
|
||||||
match->cp_next = match->cp_prev = NULL;
|
match->cp_next = match->cp_prev = NULL;
|
||||||
} else if (dir == FORWARD) {
|
} else if (dir == FORWARD) {
|
||||||
@@ -1005,6 +1012,8 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
|
|||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trigger the CompleteChanged autocmd event. Invoked each time the Insert mode
|
||||||
|
/// completion menu is changed.
|
||||||
static void trigger_complete_changed_event(int cur)
|
static void trigger_complete_changed_event(int cur)
|
||||||
{
|
{
|
||||||
static bool recursive = false;
|
static bool recursive = false;
|
||||||
@@ -1181,8 +1190,8 @@ void ins_compl_show_pum(void)
|
|||||||
#define DICT_FIRST (1) ///< use just first element in "dict"
|
#define DICT_FIRST (1) ///< use just first element in "dict"
|
||||||
#define DICT_EXACT (2) ///< "dict" is the exact name of a file
|
#define DICT_EXACT (2) ///< "dict" is the exact name of a file
|
||||||
|
|
||||||
/// Add any identifiers that match the given pattern in the list of dictionary
|
/// Add any identifiers that match the given pattern "pat" in the list of
|
||||||
/// files "dict_start" to the list of completions.
|
/// dictionary files "dict_start" to the list of completions.
|
||||||
///
|
///
|
||||||
/// @param flags DICT_FIRST and/or DICT_EXACT
|
/// @param flags DICT_FIRST and/or DICT_EXACT
|
||||||
/// @param thesaurus Thesaurus completion
|
/// @param thesaurus Thesaurus completion
|
||||||
@@ -1283,6 +1292,54 @@ theend:
|
|||||||
xfree(buf);
|
xfree(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add all the words in the line "*buf_arg" from the thesaurus file "fname"
|
||||||
|
/// skipping the word at 'skip_word'.
|
||||||
|
///
|
||||||
|
/// @return OK on success.
|
||||||
|
static int thesaurus_add_words_in_line(char *fname, char_u **buf_arg, int dir, char_u *skip_word)
|
||||||
|
{
|
||||||
|
int status = OK;
|
||||||
|
|
||||||
|
// Add the other matches on the line
|
||||||
|
char_u *ptr = *buf_arg;
|
||||||
|
while (!got_int) {
|
||||||
|
// Find start of the next word. Skip white
|
||||||
|
// space and punctuation.
|
||||||
|
ptr = find_word_start(ptr);
|
||||||
|
if (*ptr == NUL || *ptr == NL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
char_u *wstart = ptr;
|
||||||
|
|
||||||
|
// Find end of the word.
|
||||||
|
// Japanese words may have characters in
|
||||||
|
// different classes, only separate words
|
||||||
|
// with single-byte non-word characters.
|
||||||
|
while (*ptr != NUL) {
|
||||||
|
const int l = utfc_ptr2len((const char *)ptr);
|
||||||
|
|
||||||
|
if (l < 2 && !vim_iswordc(*ptr)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the word. Skip the regexp match.
|
||||||
|
if (wstart != skip_word) {
|
||||||
|
status = ins_compl_add_infercase(wstart, (int)(ptr - wstart), p_ic,
|
||||||
|
(char_u *)fname, dir, false);
|
||||||
|
if (status == FAIL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf_arg = ptr;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Process "count" dictionary/thesaurus "files" and add the text matching
|
||||||
|
/// "regmatch".
|
||||||
static void ins_compl_files(int count, char **files, int thesaurus, int flags, regmatch_T *regmatch,
|
static void ins_compl_files(int count, char **files, int thesaurus, int flags, regmatch_T *regmatch,
|
||||||
char_u *buf, Direction *dir)
|
char_u *buf, Direction *dir)
|
||||||
FUNC_ATTR_NONNULL_ARG(2, 7)
|
FUNC_ATTR_NONNULL_ARG(2, 7)
|
||||||
@@ -1320,38 +1377,10 @@ static void ins_compl_files(int count, char **files, int thesaurus, int flags, r
|
|||||||
(int)(ptr - regmatch->startp[0]),
|
(int)(ptr - regmatch->startp[0]),
|
||||||
p_ic, (char_u *)files[i], *dir, false);
|
p_ic, (char_u *)files[i], *dir, false);
|
||||||
if (thesaurus) {
|
if (thesaurus) {
|
||||||
char_u *wstart;
|
// For a thesaurus, add all the words in the line
|
||||||
|
|
||||||
// Add the other matches on the line
|
|
||||||
ptr = buf;
|
ptr = buf;
|
||||||
while (!got_int) {
|
add_r = thesaurus_add_words_in_line(files[i], &ptr, *dir,
|
||||||
// Find start of the next word. Skip white
|
regmatch->startp[0]);
|
||||||
// space and punctuation.
|
|
||||||
ptr = find_word_start(ptr);
|
|
||||||
if (*ptr == NUL || *ptr == NL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
wstart = ptr;
|
|
||||||
|
|
||||||
// Find end of the word.
|
|
||||||
// Japanese words may have characters in
|
|
||||||
// different classes, only separate words
|
|
||||||
// with single-byte non-word characters.
|
|
||||||
while (*ptr != NUL) {
|
|
||||||
const int l = utfc_ptr2len((char *)ptr);
|
|
||||||
|
|
||||||
if (l < 2 && !vim_iswordc(*ptr)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr += l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the word. Skip the regexp match.
|
|
||||||
if (wstart != regmatch->startp[0]) {
|
|
||||||
add_r = ins_compl_add_infercase(wstart, (int)(ptr - wstart),
|
|
||||||
p_ic, (char_u *)files[i], *dir, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (add_r == OK) {
|
if (add_r == OK) {
|
||||||
// if dir was BACKWARD then honor it just once
|
// if dir was BACKWARD then honor it just once
|
||||||
@@ -1536,12 +1565,12 @@ int ins_compl_bs(void)
|
|||||||
|
|
||||||
xfree(compl_leader);
|
xfree(compl_leader);
|
||||||
compl_leader = vim_strnsave(line + compl_col, (size_t)(p_off - (ptrdiff_t)compl_col));
|
compl_leader = vim_strnsave(line + compl_col, (size_t)(p_off - (ptrdiff_t)compl_col));
|
||||||
|
|
||||||
ins_compl_new_leader();
|
ins_compl_new_leader();
|
||||||
if (compl_shown_match != NULL) {
|
if (compl_shown_match != NULL) {
|
||||||
// Make sure current match is not a hidden item.
|
// Make sure current match is not a hidden item.
|
||||||
compl_curr_match = compl_shown_match;
|
compl_curr_match = compl_shown_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NUL;
|
return NUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2243,10 +2272,15 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
|
|||||||
for (size_t i = 0; i < CPT_COUNT; i++) {
|
for (size_t i = 0; i < CPT_COUNT; i++) {
|
||||||
xfree(cptext[i]);
|
xfree(cptext[i]);
|
||||||
}
|
}
|
||||||
|
tv_clear(&user_data);
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
return ins_compl_add((char_u *)word, -1, NULL,
|
int status = ins_compl_add((char_u *)word, -1, NULL, (char_u **)cptext, true,
|
||||||
(char_u **)cptext, true, &user_data, dir, flags, dup);
|
&user_data, dir, flags, dup);
|
||||||
|
if (status != OK) {
|
||||||
|
tv_clear(&user_data);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add completions from a list.
|
/// Add completions from a list.
|
||||||
@@ -2401,6 +2435,8 @@ static char_u *ins_compl_mode(void)
|
|||||||
return (char_u *)"";
|
return (char_u *)"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assign the sequence number to all the completion matches which don't have
|
||||||
|
/// one assigned yet.
|
||||||
static void ins_compl_update_sequence_numbers(void)
|
static void ins_compl_update_sequence_numbers(void)
|
||||||
{
|
{
|
||||||
int number = 0;
|
int number = 0;
|
||||||
@@ -2582,8 +2618,8 @@ enum {
|
|||||||
/// st->dict_f - flag specifying whether "dict" is an exact file name or not
|
/// st->dict_f - flag specifying whether "dict" is an exact file name or not
|
||||||
///
|
///
|
||||||
/// @return INS_COMPL_CPT_OK if the next value is processed successfully.
|
/// @return INS_COMPL_CPT_OK if the next value is processed successfully.
|
||||||
/// INS_COMPL_CPT_CONT to skip the current value and process the next
|
/// INS_COMPL_CPT_CONT to skip the current completion source matching
|
||||||
/// option value.
|
/// the "st->e_cpt" option value and process the next matching source.
|
||||||
/// INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed.
|
/// INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed.
|
||||||
static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_arg,
|
static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_arg,
|
||||||
pos_T *start_match_pos)
|
pos_T *start_match_pos)
|
||||||
@@ -3764,7 +3800,7 @@ static int get_userdefined_compl_info(colnr_T curs_col)
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset extended parameters of completion, when start new
|
// Reset extended parameters of completion, when starting new
|
||||||
// completion.
|
// completion.
|
||||||
compl_opt_refresh_always = false;
|
compl_opt_refresh_always = false;
|
||||||
|
|
||||||
@@ -4154,6 +4190,7 @@ int ins_complete(int c, bool enable_pum)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove (if needed) and show the popup menu
|
||||||
static void show_pum(int prev_w_wrow, int prev_w_leftcol)
|
static void show_pum(int prev_w_wrow, int prev_w_leftcol)
|
||||||
{
|
{
|
||||||
// RedrawingDisabled may be set when invoked through complete().
|
// RedrawingDisabled may be set when invoked through complete().
|
||||||
|
|||||||
@@ -713,23 +713,32 @@ endfunc
|
|||||||
|
|
||||||
func Test_edit_CTRL_N()
|
func Test_edit_CTRL_N()
|
||||||
" Check keyword completion
|
" Check keyword completion
|
||||||
|
" for e in ['latin1', 'utf-8']
|
||||||
|
for e in ['utf-8']
|
||||||
|
exe 'set encoding=' .. e
|
||||||
new
|
new
|
||||||
set complete=.
|
set complete=.
|
||||||
call setline(1, ['INFER', 'loWER', '', '', ])
|
call setline(1, ['INFER', 'loWER', '', '', ])
|
||||||
call cursor(3, 1)
|
call cursor(3, 1)
|
||||||
call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix")
|
call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix")
|
||||||
call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
|
call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
|
||||||
call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'))
|
call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'), e)
|
||||||
%d
|
%d
|
||||||
call setline(1, ['INFER', 'loWER', '', '', ])
|
call setline(1, ['INFER', 'loWER', '', '', ])
|
||||||
call cursor(3, 1)
|
call cursor(3, 1)
|
||||||
set ignorecase infercase
|
set ignorecase infercase
|
||||||
call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
|
call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
|
||||||
call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
|
call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
|
||||||
call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'))
|
call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'), e)
|
||||||
|
set noignorecase noinfercase
|
||||||
set noignorecase noinfercase complete&
|
%d
|
||||||
|
call setline(1, ['one word', 'two word'])
|
||||||
|
exe "normal! Goo\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal('one word', getline(3))
|
||||||
|
%d
|
||||||
|
set complete&
|
||||||
bw!
|
bw!
|
||||||
|
endfor
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_edit_CTRL_O()
|
func Test_edit_CTRL_O()
|
||||||
@@ -893,6 +902,24 @@ func Test_edit_CTRL_T()
|
|||||||
bw!
|
bw!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test thesaurus completion with different encodings
|
||||||
|
func Test_thesaurus_complete_with_encoding()
|
||||||
|
call writefile(['angry furious mad enraged'], 'Xthesaurus')
|
||||||
|
set thesaurus=Xthesaurus
|
||||||
|
" for e in ['latin1', 'utf-8']
|
||||||
|
for e in ['utf-8']
|
||||||
|
exe 'set encoding=' .. e
|
||||||
|
new
|
||||||
|
call setline(1, 'mad')
|
||||||
|
call cursor(1, 1)
|
||||||
|
call feedkeys("A\<c-x>\<c-t>\<cr>\<esc>", 'tnix')
|
||||||
|
call assert_equal(['mad', ''], getline(1, '$'))
|
||||||
|
bw!
|
||||||
|
endfor
|
||||||
|
set thesaurus=
|
||||||
|
call delete('Xthesaurus')
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Test 'thesaurusfunc'
|
" Test 'thesaurusfunc'
|
||||||
func MyThesaurus(findstart, base)
|
func MyThesaurus(findstart, base)
|
||||||
let mythesaurus = [
|
let mythesaurus = [
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ func Test_ins_complete()
|
|||||||
call assert_equal('Xtest11.one', getline('.'))
|
call assert_equal('Xtest11.one', getline('.'))
|
||||||
normal ddk
|
normal ddk
|
||||||
|
|
||||||
|
" Test for expanding a non-existing filename
|
||||||
|
exe "normal oa1b2X3Y4\<C-X>\<C-F>"
|
||||||
|
call assert_equal('a1b2X3Y4', getline('.'))
|
||||||
|
normal ddk
|
||||||
|
|
||||||
set cpt=w
|
set cpt=w
|
||||||
" checks make_cyclic in other window
|
" checks make_cyclic in other window
|
||||||
exe "normal oST\<C-N>\<C-P>\<C-P>\<C-P>\<C-P>"
|
exe "normal oST\<C-N>\<C-P>\<C-P>\<C-P>\<C-P>"
|
||||||
@@ -682,6 +687,21 @@ func Test_complete_func_error()
|
|||||||
call assert_equal([], complete_info(['items']).items)
|
call assert_equal([], complete_info(['items']).items)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for recursively starting completion mode using complete()
|
||||||
|
func Test_recursive_complete_func()
|
||||||
|
func ListColors()
|
||||||
|
call complete(5, ["red", "blue"])
|
||||||
|
return ''
|
||||||
|
endfunc
|
||||||
|
new
|
||||||
|
call setline(1, ['a1', 'a2'])
|
||||||
|
set complete=.
|
||||||
|
exe "normal Goa\<C-X>\<C-L>\<C-R>=ListColors()\<CR>\<C-N>"
|
||||||
|
call assert_equal('a2blue', getline(3))
|
||||||
|
delfunc ListColors
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Test for completing words following a completed word in a line
|
" Test for completing words following a completed word in a line
|
||||||
func Test_complete_wrapscan()
|
func Test_complete_wrapscan()
|
||||||
" complete words from another buffer
|
" complete words from another buffer
|
||||||
@@ -905,6 +925,322 @@ func Test_issue_7021()
|
|||||||
set completeslash=
|
set completeslash=
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for 'longest' setting in 'completeopt' with latin1 and utf-8 encodings
|
||||||
|
func Test_complete_longest_match()
|
||||||
|
" for e in ['latin1', 'utf-8']
|
||||||
|
for e in ['utf-8']
|
||||||
|
exe 'set encoding=' .. e
|
||||||
|
new
|
||||||
|
set complete=.
|
||||||
|
set completeopt=menu,longest
|
||||||
|
call setline(1, ['pfx_a1', 'pfx_a12', 'pfx_a123', 'pfx_b1'])
|
||||||
|
exe "normal Gopfx\<C-P>"
|
||||||
|
call assert_equal('pfx_', getline(5))
|
||||||
|
bw!
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Test for completing additional words with longest match set
|
||||||
|
new
|
||||||
|
call setline(1, ['abc1', 'abd2'])
|
||||||
|
exe "normal Goab\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal('ab', getline(3))
|
||||||
|
bw!
|
||||||
|
set complete& completeopt&
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for removing the first displayed completion match and selecting the
|
||||||
|
" match just before that.
|
||||||
|
func Test_complete_erase_firstmatch()
|
||||||
|
new
|
||||||
|
call setline(1, ['a12', 'a34', 'a56'])
|
||||||
|
set complete=.
|
||||||
|
exe "normal Goa\<C-P>\<BS>\<BS>3\<CR>"
|
||||||
|
call assert_equal('a34', getline('$'))
|
||||||
|
set complete&
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing words from unloaded buffers
|
||||||
|
func Test_complete_from_unloadedbuf()
|
||||||
|
call writefile(['abc'], "Xfile1")
|
||||||
|
call writefile(['def'], "Xfile2")
|
||||||
|
edit Xfile1
|
||||||
|
edit Xfile2
|
||||||
|
new | close
|
||||||
|
enew
|
||||||
|
bunload Xfile1 Xfile2
|
||||||
|
set complete=u
|
||||||
|
" complete from an unloaded buffer
|
||||||
|
exe "normal! ia\<C-P>"
|
||||||
|
call assert_equal('abc', getline(1))
|
||||||
|
exe "normal! od\<C-P>"
|
||||||
|
call assert_equal('def', getline(2))
|
||||||
|
set complete&
|
||||||
|
%bw!
|
||||||
|
call delete("Xfile1")
|
||||||
|
call delete("Xfile2")
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing whole lines from unloaded buffers
|
||||||
|
func Test_complete_wholeline_unloadedbuf()
|
||||||
|
call writefile(['a line1', 'a line2', 'a line3'], "Xfile1")
|
||||||
|
edit Xfile1
|
||||||
|
enew
|
||||||
|
set complete=u
|
||||||
|
exe "normal! ia\<C-X>\<C-L>\<C-P>"
|
||||||
|
call assert_equal('a line2', getline(1))
|
||||||
|
%d
|
||||||
|
" completing from an unlisted buffer should fail
|
||||||
|
bdel Xfile1
|
||||||
|
exe "normal! ia\<C-X>\<C-L>\<C-P>"
|
||||||
|
call assert_equal('a', getline(1))
|
||||||
|
set complete&
|
||||||
|
%bw!
|
||||||
|
call delete("Xfile1")
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing words from unlisted buffers
|
||||||
|
func Test_complete_from_unlistedbuf()
|
||||||
|
call writefile(['abc'], "Xfile1")
|
||||||
|
call writefile(['def'], "Xfile2")
|
||||||
|
edit Xfile1
|
||||||
|
edit Xfile2
|
||||||
|
new | close
|
||||||
|
bdel Xfile1 Xfile2
|
||||||
|
set complete=U
|
||||||
|
" complete from an unlisted buffer
|
||||||
|
exe "normal! ia\<C-P>"
|
||||||
|
call assert_equal('abc', getline(1))
|
||||||
|
exe "normal! od\<C-P>"
|
||||||
|
call assert_equal('def', getline(2))
|
||||||
|
set complete&
|
||||||
|
%bw!
|
||||||
|
call delete("Xfile1")
|
||||||
|
call delete("Xfile2")
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing whole lines from unlisted buffers
|
||||||
|
func Test_complete_wholeline_unlistedbuf()
|
||||||
|
call writefile(['a line1', 'a line2', 'a line3'], "Xfile1")
|
||||||
|
edit Xfile1
|
||||||
|
enew
|
||||||
|
set complete=U
|
||||||
|
" completing from a unloaded buffer should fail
|
||||||
|
exe "normal! ia\<C-X>\<C-L>\<C-P>"
|
||||||
|
call assert_equal('a', getline(1))
|
||||||
|
%d
|
||||||
|
bdel Xfile1
|
||||||
|
exe "normal! ia\<C-X>\<C-L>\<C-P>"
|
||||||
|
call assert_equal('a line2', getline(1))
|
||||||
|
set complete&
|
||||||
|
%bw!
|
||||||
|
call delete("Xfile1")
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for adding a multibyte character using CTRL-L in completion mode
|
||||||
|
func Test_complete_mbyte_char_add()
|
||||||
|
new
|
||||||
|
set complete=.
|
||||||
|
call setline(1, 'abė')
|
||||||
|
exe "normal! oa\<C-P>\<BS>\<BS>\<C-L>\<C-L>"
|
||||||
|
call assert_equal('abė', getline(2))
|
||||||
|
" Test for a leader with multibyte character
|
||||||
|
%d
|
||||||
|
call setline(1, 'abėĕ')
|
||||||
|
exe "normal! oabė\<C-P>"
|
||||||
|
call assert_equal('abėĕ', getline(2))
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for using <C-X><C-P> for local expansion even if 'complete' is set to
|
||||||
|
" not to complete matches from the local buffer. Also test using multiple
|
||||||
|
" <C-X> to cancel the current completion mode.
|
||||||
|
func Test_complete_local_expansion()
|
||||||
|
new
|
||||||
|
set complete=t
|
||||||
|
call setline(1, ['abc', 'def'])
|
||||||
|
exe "normal! Go\<C-X>\<C-P>"
|
||||||
|
call assert_equal("def", getline(3))
|
||||||
|
exe "normal! Go\<C-P>"
|
||||||
|
call assert_equal("", getline(4))
|
||||||
|
exe "normal! Go\<C-X>\<C-N>"
|
||||||
|
call assert_equal("abc", getline(5))
|
||||||
|
exe "normal! Go\<C-N>"
|
||||||
|
call assert_equal("", getline(6))
|
||||||
|
|
||||||
|
" use multiple <C-X> to cancel the previous completion mode
|
||||||
|
exe "normal! Go\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal("", getline(7))
|
||||||
|
exe "normal! Go\<C-P>\<C-X>\<C-X>\<C-P>"
|
||||||
|
call assert_equal("", getline(8))
|
||||||
|
exe "normal! Go\<C-P>\<C-X>\<C-X>\<C-X>\<C-P>"
|
||||||
|
call assert_equal("abc", getline(9))
|
||||||
|
|
||||||
|
" interrupt the current completion mode
|
||||||
|
set completeopt=menu,noinsert
|
||||||
|
exe "normal! Go\<C-X>\<C-F>\<C-X>\<C-X>\<C-P>\<C-Y>"
|
||||||
|
call assert_equal("abc", getline(10))
|
||||||
|
|
||||||
|
" when only one <C-X> is used to interrupt, do normal expansion
|
||||||
|
exe "normal! Go\<C-X>\<C-F>\<C-X>\<C-P>"
|
||||||
|
call assert_equal("", getline(11))
|
||||||
|
set completeopt&
|
||||||
|
|
||||||
|
" using two <C-X> in non-completion mode and restarting the same mode
|
||||||
|
exe "normal! God\<C-X>\<C-X>\<C-P>\<C-X>\<C-X>\<C-P>\<C-Y>"
|
||||||
|
call assert_equal("def", getline(12))
|
||||||
|
|
||||||
|
" test for adding a match from the original empty text
|
||||||
|
%d
|
||||||
|
call setline(1, 'abc def g')
|
||||||
|
exe "normal! o\<C-X>\<C-P>\<C-N>\<C-X>\<C-P>"
|
||||||
|
call assert_equal('def', getline(2))
|
||||||
|
exe "normal! 0C\<C-X>\<C-N>\<C-P>\<C-X>\<C-N>"
|
||||||
|
call assert_equal('abc', getline(2))
|
||||||
|
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for undoing changes after a insert-mode completion
|
||||||
|
func Test_complete_undo()
|
||||||
|
new
|
||||||
|
set complete=.
|
||||||
|
" undo with 'ignorecase'
|
||||||
|
call setline(1, ['ABOVE', 'BELOW'])
|
||||||
|
set ignorecase
|
||||||
|
exe "normal! Goab\<C-G>u\<C-P>"
|
||||||
|
call assert_equal("ABOVE", getline(3))
|
||||||
|
undo
|
||||||
|
call assert_equal("ab", getline(3))
|
||||||
|
set ignorecase&
|
||||||
|
%d
|
||||||
|
" undo with longest match
|
||||||
|
set completeopt=menu,longest
|
||||||
|
call setline(1, ['above', 'about'])
|
||||||
|
exe "normal! Goa\<C-G>u\<C-P>"
|
||||||
|
call assert_equal("abo", getline(3))
|
||||||
|
undo
|
||||||
|
call assert_equal("a", getline(3))
|
||||||
|
set completeopt&
|
||||||
|
%d
|
||||||
|
" undo for line completion
|
||||||
|
call setline(1, ['above that change', 'below that change'])
|
||||||
|
exe "normal! Goabove\<C-G>u\<C-X>\<C-L>"
|
||||||
|
call assert_equal("above that change", getline(3))
|
||||||
|
undo
|
||||||
|
call assert_equal("above", getline(3))
|
||||||
|
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing a very long word
|
||||||
|
func Test_complete_long_word()
|
||||||
|
set complete&
|
||||||
|
new
|
||||||
|
call setline(1, repeat('x', 950) .. ' one two three')
|
||||||
|
exe "normal! Gox\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal(repeat('x', 950) .. ' one two three', getline(2))
|
||||||
|
%d
|
||||||
|
" should fail when more than 950 characters are in a word
|
||||||
|
call setline(1, repeat('x', 951) .. ' one two three')
|
||||||
|
exe "normal! Gox\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal(repeat('x', 951), getline(2))
|
||||||
|
|
||||||
|
" Test for adding a very long word to an existing completion
|
||||||
|
%d
|
||||||
|
call setline(1, ['abc', repeat('x', 1016) .. '012345'])
|
||||||
|
exe "normal! Goab\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal('abc ' .. repeat('x', 1016) .. '0123', getline(3))
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for some fields in the complete items used by complete()
|
||||||
|
func Test_complete_items()
|
||||||
|
func CompleteItems(idx)
|
||||||
|
let items = [[#{word: "one", dup: 1, user_data: 'u1'}, #{word: "one", dup: 1, user_data: 'u2'}],
|
||||||
|
\ [#{word: "one", dup: 0, user_data: 'u3'}, #{word: "one", dup: 0, user_data: 'u4'}],
|
||||||
|
\ [#{word: "one", icase: 1, user_data: 'u7'}, #{word: "oNE", icase: 1, user_data: 'u8'}],
|
||||||
|
\ [#{user_data: 'u9'}],
|
||||||
|
\ [#{word: "", user_data: 'u10'}],
|
||||||
|
\ [#{word: "", empty: 1, user_data: 'u11'}]]
|
||||||
|
call complete(col('.'), items[a:idx])
|
||||||
|
return ''
|
||||||
|
endfunc
|
||||||
|
new
|
||||||
|
exe "normal! i\<C-R>=CompleteItems(0)\<CR>\<C-N>\<C-Y>"
|
||||||
|
call assert_equal('u2', v:completed_item.user_data)
|
||||||
|
call assert_equal('one', getline(1))
|
||||||
|
exe "normal! o\<C-R>=CompleteItems(1)\<CR>\<C-Y>"
|
||||||
|
call assert_equal('u3', v:completed_item.user_data)
|
||||||
|
call assert_equal('one', getline(2))
|
||||||
|
exe "normal! o\<C-R>=CompleteItems(1)\<CR>\<C-N>"
|
||||||
|
call assert_equal('', getline(3))
|
||||||
|
set completeopt=menu,noinsert
|
||||||
|
exe "normal! o\<C-R>=CompleteItems(2)\<CR>one\<C-N>\<C-Y>"
|
||||||
|
call assert_equal('oNE', getline(4))
|
||||||
|
call assert_equal('u8', v:completed_item.user_data)
|
||||||
|
set completeopt&
|
||||||
|
exe "normal! o\<C-R>=CompleteItems(3)\<CR>"
|
||||||
|
call assert_equal('', getline(5))
|
||||||
|
exe "normal! o\<C-R>=CompleteItems(4)\<CR>"
|
||||||
|
call assert_equal('', getline(6))
|
||||||
|
exe "normal! o\<C-R>=CompleteItems(5)\<CR>"
|
||||||
|
call assert_equal('', getline(7))
|
||||||
|
call assert_equal('u11', v:completed_item.user_data)
|
||||||
|
" pass invalid argument to complete()
|
||||||
|
let cmd = "normal! o\<C-R>=complete(1, [[]])\<CR>"
|
||||||
|
call assert_fails('exe cmd', 'E730:')
|
||||||
|
bw!
|
||||||
|
delfunc CompleteItems
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for the "refresh" item in the dict returned by an insert completion
|
||||||
|
" function
|
||||||
|
func Test_complete_item_refresh_always()
|
||||||
|
let g:CallCount = 0
|
||||||
|
func! Tcomplete(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
" locate the start of the word
|
||||||
|
let line = getline('.')
|
||||||
|
let start = col('.') - 1
|
||||||
|
while start > 0 && line[start - 1] =~ '\a'
|
||||||
|
let start -= 1
|
||||||
|
endwhile
|
||||||
|
return start
|
||||||
|
else
|
||||||
|
let g:CallCount += 1
|
||||||
|
let res = ["update1", "update12", "update123"]
|
||||||
|
return #{words: res, refresh: 'always'}
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
new
|
||||||
|
set completeopt=menu,longest
|
||||||
|
set completefunc=Tcomplete
|
||||||
|
exe "normal! iup\<C-X>\<C-U>\<BS>\<BS>\<BS>\<BS>\<BS>"
|
||||||
|
call assert_equal('up', getline(1))
|
||||||
|
call assert_equal(2, g:CallCount)
|
||||||
|
set completeopt&
|
||||||
|
set completefunc&
|
||||||
|
bw!
|
||||||
|
delfunc Tcomplete
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing from a thesaurus file without read permission
|
||||||
|
func Test_complete_unreadable_thesaurus_file()
|
||||||
|
CheckUnix
|
||||||
|
CheckNotRoot
|
||||||
|
|
||||||
|
call writefile(['about', 'above'], 'Xfile')
|
||||||
|
call setfperm('Xfile', '---r--r--')
|
||||||
|
new
|
||||||
|
set complete=sXfile
|
||||||
|
exe "normal! ia\<C-P>"
|
||||||
|
call assert_equal('a', getline(1))
|
||||||
|
bw!
|
||||||
|
call delete('Xfile')
|
||||||
|
set complete&
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Test to ensure 'Scanning...' messages are not recorded in messages history
|
" Test to ensure 'Scanning...' messages are not recorded in messages history
|
||||||
func Test_z1_complete_no_history()
|
func Test_z1_complete_no_history()
|
||||||
new
|
new
|
||||||
|
|||||||
@@ -248,6 +248,8 @@ func Test_mapset()
|
|||||||
bwipe!
|
bwipe!
|
||||||
|
|
||||||
call assert_fails('call mapset([], v:false, {})', 'E730:')
|
call assert_fails('call mapset([], v:false, {})', 'E730:')
|
||||||
|
call assert_fails('call mapset("i", 0, "")', 'E715:')
|
||||||
|
call assert_fails('call mapset("i", 0, {})', 'E460:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Check_ctrlb_map(d, check_alt)
|
func Check_ctrlb_map(d, check_alt)
|
||||||
|
|||||||
Reference in New Issue
Block a user