mirror of
https://github.com/neovim/neovim.git
synced 2025-10-13 13:26:06 +00:00
vim-patch:8.2.3937: Insert mode completion function is too long
Problem: Insert mode completion function is too long.
Solution: Refactor into multiple functions. (Yegappan Lakshmanan,
closes vim/vim#9423)
edc6f10390
Cherry-pick a typo fix from patch 8.2.3637.
This commit is contained in:
@@ -2464,6 +2464,422 @@ static bool thesaurus_func_complete(int type)
|
|||||||
&& (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
|
&& (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return value of process_next_cpt_value()
|
||||||
|
enum {
|
||||||
|
INS_COMPL_CPT_OK = 1,
|
||||||
|
INS_COMPL_CPT_CONT,
|
||||||
|
INS_COMPL_CPT_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Process the next 'complete' option value in "e_cpt_arg".
|
||||||
|
///
|
||||||
|
/// If successful, the arguments are set as below:
|
||||||
|
/// e_cpt_arg - pointer to the next option value in 'e_cpt_arg'
|
||||||
|
/// compl_type_arg - type of insert mode completion to use
|
||||||
|
/// found_all_arg - all matches of this type are found
|
||||||
|
/// buf_arg - search for completions in this buffer
|
||||||
|
/// first_match_pos - position of the first completion match
|
||||||
|
/// last_match_pos - position of the last completion match
|
||||||
|
/// set_match_pos - true if the first match position should be saved to avoid
|
||||||
|
/// loops after the search wraps around.
|
||||||
|
/// dict - name of the dictionary or thesaurus file to search
|
||||||
|
/// 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.
|
||||||
|
/// INS_COMPL_CPT_CONT to skip the current value and process the next
|
||||||
|
/// option value.
|
||||||
|
/// INS_COMPL_CPT_END if all the values in "e_cpt" are processed.
|
||||||
|
static int process_next_cpt_value(char **e_cpt_arg, int *compl_type_arg, bool *found_all_arg,
|
||||||
|
buf_T **buf_arg, pos_T *start_match_pos, pos_T *first_match_pos,
|
||||||
|
pos_T *last_match_pos, bool *set_match_pos, char_u **dict_arg,
|
||||||
|
int *dict_flag)
|
||||||
|
{
|
||||||
|
char *e_cpt = *e_cpt_arg;
|
||||||
|
int compl_type = -1;
|
||||||
|
int status = INS_COMPL_CPT_OK;
|
||||||
|
buf_T *buf = *buf_arg;
|
||||||
|
bool found_all = false;
|
||||||
|
char_u *dict = NULL;
|
||||||
|
int dict_f = 0;
|
||||||
|
|
||||||
|
while (*e_cpt == ',' || *e_cpt == ' ') {
|
||||||
|
e_cpt++;
|
||||||
|
}
|
||||||
|
if (*e_cpt == '.' && !curbuf->b_scanned) {
|
||||||
|
buf = curbuf;
|
||||||
|
*first_match_pos = *start_match_pos;
|
||||||
|
// Move the cursor back one character so that ^N can match the
|
||||||
|
// word immediately after the cursor.
|
||||||
|
if (ctrl_x_mode_normal() && dec(first_match_pos) < 0) {
|
||||||
|
// Move the cursor to after the last character in the
|
||||||
|
// buffer, so that word at start of buffer is found
|
||||||
|
// correctly.
|
||||||
|
first_match_pos->lnum = buf->b_ml.ml_line_count;
|
||||||
|
first_match_pos->col = (colnr_T)STRLEN(ml_get(first_match_pos->lnum));
|
||||||
|
}
|
||||||
|
*last_match_pos = *first_match_pos;
|
||||||
|
compl_type = 0;
|
||||||
|
|
||||||
|
// Remember the first match so that the loop stops when we
|
||||||
|
// wrap and come back there a second time.
|
||||||
|
*set_match_pos = true;
|
||||||
|
} else if (vim_strchr("buwU", *e_cpt) != NULL
|
||||||
|
&& (buf = ins_compl_next_buf(buf, *e_cpt)) != curbuf) {
|
||||||
|
// Scan a buffer, but not the current one.
|
||||||
|
if (buf->b_ml.ml_mfp != NULL) { // loaded buffer
|
||||||
|
compl_started = true;
|
||||||
|
first_match_pos->col = last_match_pos->col = 0;
|
||||||
|
first_match_pos->lnum = buf->b_ml.ml_line_count + 1;
|
||||||
|
last_match_pos->lnum = 0;
|
||||||
|
compl_type = 0;
|
||||||
|
} else { // unloaded buffer, scan like dictionary
|
||||||
|
found_all = true;
|
||||||
|
if (buf->b_fname == NULL) {
|
||||||
|
status = INS_COMPL_CPT_CONT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
compl_type = CTRL_X_DICTIONARY;
|
||||||
|
dict = (char_u *)buf->b_fname;
|
||||||
|
dict_f = DICT_EXACT;
|
||||||
|
}
|
||||||
|
msg_hist_off = true; // reset in msg_trunc_attr()
|
||||||
|
vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
|
||||||
|
buf->b_fname == NULL
|
||||||
|
? buf_spname(buf)
|
||||||
|
: buf->b_sfname == NULL
|
||||||
|
? buf->b_fname
|
||||||
|
: buf->b_sfname);
|
||||||
|
(void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
|
||||||
|
} else if (*e_cpt == NUL) {
|
||||||
|
status = INS_COMPL_CPT_END;
|
||||||
|
} else {
|
||||||
|
if (ctrl_x_mode_line_or_eval()) {
|
||||||
|
compl_type = -1;
|
||||||
|
} else if (*e_cpt == 'k' || *e_cpt == 's') {
|
||||||
|
if (*e_cpt == 'k') {
|
||||||
|
compl_type = CTRL_X_DICTIONARY;
|
||||||
|
} else {
|
||||||
|
compl_type = CTRL_X_THESAURUS;
|
||||||
|
}
|
||||||
|
if (*++e_cpt != ',' && *e_cpt != NUL) {
|
||||||
|
dict = (char_u *)e_cpt;
|
||||||
|
dict_f = DICT_FIRST;
|
||||||
|
}
|
||||||
|
} else if (*e_cpt == 'i') {
|
||||||
|
compl_type = CTRL_X_PATH_PATTERNS;
|
||||||
|
} else if (*e_cpt == 'd') {
|
||||||
|
compl_type = CTRL_X_PATH_DEFINES;
|
||||||
|
} else if (*e_cpt == ']' || *e_cpt == 't') {
|
||||||
|
msg_hist_off = true; // reset in msg_trunc_attr()
|
||||||
|
compl_type = CTRL_X_TAGS;
|
||||||
|
vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags."));
|
||||||
|
(void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
|
||||||
|
} else {
|
||||||
|
compl_type = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// in any case e_cpt is advanced to the next entry
|
||||||
|
(void)copy_option_part(&e_cpt, (char *)IObuff, IOSIZE, ",");
|
||||||
|
|
||||||
|
found_all = true;
|
||||||
|
if (compl_type == -1) {
|
||||||
|
status = INS_COMPL_CPT_CONT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
*e_cpt_arg = e_cpt;
|
||||||
|
*compl_type_arg = compl_type;
|
||||||
|
*found_all_arg = found_all;
|
||||||
|
*buf_arg = buf;
|
||||||
|
*dict_arg = dict;
|
||||||
|
*dict_flag = dict_f;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of identifiers or defines matching "compl_pattern" in
|
||||||
|
/// included files.
|
||||||
|
static void get_next_include_file_completion(int compl_type)
|
||||||
|
{
|
||||||
|
find_pattern_in_path((char_u *)compl_pattern, compl_direction,
|
||||||
|
STRLEN(compl_pattern), false, false,
|
||||||
|
((compl_type == CTRL_X_PATH_DEFINES
|
||||||
|
&& !(compl_cont_status & CONT_SOL))
|
||||||
|
? FIND_DEFINE : FIND_ANY),
|
||||||
|
1L, ACTION_EXPAND, 1, MAXLNUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of words matching "compl_pattern" in dictionary or
|
||||||
|
/// thesaurus files.
|
||||||
|
static void get_next_dict_tsr_completion(int compl_type, char_u **dict, int dict_f)
|
||||||
|
{
|
||||||
|
if (thesaurus_func_complete(compl_type)) {
|
||||||
|
expand_by_function(compl_type, (char_u *)compl_pattern);
|
||||||
|
} else {
|
||||||
|
ins_compl_dictionaries(*dict != NULL ? *dict
|
||||||
|
: (compl_type == CTRL_X_THESAURUS
|
||||||
|
? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
|
||||||
|
: (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)),
|
||||||
|
(char_u *)compl_pattern,
|
||||||
|
*dict != NULL ? dict_f : 0,
|
||||||
|
compl_type == CTRL_X_THESAURUS);
|
||||||
|
}
|
||||||
|
*dict = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of tag names matching "compl_pattern".
|
||||||
|
static void get_next_tag_completion(void)
|
||||||
|
{
|
||||||
|
// set p_ic according to p_ic, p_scs and pat for find_tags().
|
||||||
|
const int save_p_ic = p_ic;
|
||||||
|
p_ic = ignorecase((char_u *)compl_pattern);
|
||||||
|
|
||||||
|
// Find up to TAG_MANY matches. Avoids that an enormous number
|
||||||
|
// of matches is found when compl_pattern is empty
|
||||||
|
g_tag_at_cursor = true;
|
||||||
|
char **matches;
|
||||||
|
int num_matches;
|
||||||
|
if (find_tags((char_u *)compl_pattern, &num_matches, &matches,
|
||||||
|
TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
|
||||||
|
| (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0),
|
||||||
|
TAG_MANY, (char_u *)curbuf->b_ffname) == OK && num_matches > 0) {
|
||||||
|
ins_compl_add_matches(num_matches, matches, p_ic);
|
||||||
|
}
|
||||||
|
g_tag_at_cursor = false;
|
||||||
|
p_ic = save_p_ic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of filename matching "compl_pattern".
|
||||||
|
static void get_next_filename_completion(void)
|
||||||
|
{
|
||||||
|
char **matches;
|
||||||
|
int num_matches;
|
||||||
|
if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
|
||||||
|
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// May change home directory back to "~".
|
||||||
|
tilde_replace((char_u *)compl_pattern, num_matches, matches);
|
||||||
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
|
if (curbuf->b_p_csl[0] != NUL) {
|
||||||
|
for (int i = 0; i < num_matches; i++) {
|
||||||
|
char_u *ptr = matches[i];
|
||||||
|
while (*ptr != NUL) {
|
||||||
|
if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
|
||||||
|
*ptr = '/';
|
||||||
|
} else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') {
|
||||||
|
*ptr = '\\';
|
||||||
|
}
|
||||||
|
ptr += utfc_ptr2len(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of command-line completions matching "compl_pattern".
|
||||||
|
static void get_next_cmdline_completion(void)
|
||||||
|
{
|
||||||
|
char **matches;
|
||||||
|
int num_matches;
|
||||||
|
if (expand_cmdline(&compl_xp, (char_u *)compl_pattern,
|
||||||
|
(int)STRLEN(compl_pattern),
|
||||||
|
&num_matches, &matches) == EXPAND_OK) {
|
||||||
|
ins_compl_add_matches(num_matches, matches, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of spell suggestions matching "compl_pattern".
|
||||||
|
static void get_next_spell_completion(linenr_T lnum)
|
||||||
|
{
|
||||||
|
char **matches;
|
||||||
|
int num_matches = expand_spelling(lnum, (char_u *)compl_pattern, &matches);
|
||||||
|
if (num_matches > 0) {
|
||||||
|
ins_compl_add_matches(num_matches, matches, p_ic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next set of words matching "compl_pattern" for default completion(s)
|
||||||
|
/// (normal ^P/^N and ^X^L).
|
||||||
|
/// Search for "compl_pattern" in the buffer "ins_buf" starting from the
|
||||||
|
/// position "start_pos" in the "compl_direction" direction. If "save_match_pos"
|
||||||
|
/// is true, then set the "first_match_pos" and "last_match_pos".
|
||||||
|
///
|
||||||
|
/// @param ins_buf buffer being scanned
|
||||||
|
/// @param start_pos search start position
|
||||||
|
/// @param cur_match_pos current match position
|
||||||
|
/// @param prev_match_pos previous match position
|
||||||
|
/// @param save_match_pos set first_match_pos/last_match_pos
|
||||||
|
/// @param first_match_pos first match position
|
||||||
|
/// @param last_match_pos last match position
|
||||||
|
/// @param scan_curbuf scan current buffer for completion
|
||||||
|
///
|
||||||
|
/// @return OK if a new next match is found, otherwise FAIL.
|
||||||
|
static int get_next_default_completion(buf_T *ins_buf, pos_T *start_pos, pos_T *cur_match_pos,
|
||||||
|
pos_T *prev_match_pos, bool *save_match_pos,
|
||||||
|
pos_T *first_match_pos, pos_T *last_match_pos,
|
||||||
|
bool scan_curbuf)
|
||||||
|
{
|
||||||
|
// If 'infercase' is set, don't use 'smartcase' here
|
||||||
|
const int save_p_scs = p_scs;
|
||||||
|
assert(ins_buf);
|
||||||
|
if (ins_buf->b_p_inf) {
|
||||||
|
p_scs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffers other than curbuf are scanned from the beginning or the
|
||||||
|
// end but never from the middle, thus setting nowrapscan in this
|
||||||
|
// buffers is a good idea, on the other hand, we always set
|
||||||
|
// wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
|
||||||
|
const int save_p_ws = p_ws;
|
||||||
|
if (ins_buf != curbuf) {
|
||||||
|
p_ws = false;
|
||||||
|
} else if (scan_curbuf) {
|
||||||
|
p_ws = true;
|
||||||
|
}
|
||||||
|
bool looped_around = false;
|
||||||
|
int found_new_match = FAIL;
|
||||||
|
for (;;) {
|
||||||
|
bool cont_s_ipos = false;
|
||||||
|
|
||||||
|
msg_silent++; // Don't want messages for wrapscan.
|
||||||
|
// ctrl_x_mode_line_or_eval() || word-wise search that
|
||||||
|
// has added a word that was at the beginning of the line.
|
||||||
|
if (ctrl_x_mode_line_or_eval()
|
||||||
|
|| (compl_cont_status & CONT_SOL)) {
|
||||||
|
found_new_match = search_for_exact_line(ins_buf, cur_match_pos,
|
||||||
|
compl_direction, (char_u *)compl_pattern);
|
||||||
|
} else {
|
||||||
|
found_new_match = searchit(NULL, ins_buf, cur_match_pos, NULL,
|
||||||
|
compl_direction,
|
||||||
|
(char_u *)compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
|
||||||
|
RE_LAST, NULL);
|
||||||
|
}
|
||||||
|
msg_silent--;
|
||||||
|
if (!compl_started || *save_match_pos) {
|
||||||
|
// set "compl_started" even on fail
|
||||||
|
compl_started = true;
|
||||||
|
*first_match_pos = *cur_match_pos;
|
||||||
|
*last_match_pos = *cur_match_pos;
|
||||||
|
*save_match_pos = false;
|
||||||
|
} else if (first_match_pos->lnum == last_match_pos->lnum
|
||||||
|
&& first_match_pos->col == last_match_pos->col) {
|
||||||
|
found_new_match = FAIL;
|
||||||
|
} else if ((compl_direction == FORWARD)
|
||||||
|
&& (prev_match_pos->lnum > cur_match_pos->lnum
|
||||||
|
|| (prev_match_pos->lnum == cur_match_pos->lnum
|
||||||
|
&& prev_match_pos->col >= cur_match_pos->col))) {
|
||||||
|
if (looped_around) {
|
||||||
|
found_new_match = FAIL;
|
||||||
|
} else {
|
||||||
|
looped_around = true;
|
||||||
|
}
|
||||||
|
} else if ((compl_direction != FORWARD)
|
||||||
|
&& (prev_match_pos->lnum < cur_match_pos->lnum
|
||||||
|
|| (prev_match_pos->lnum == cur_match_pos->lnum
|
||||||
|
&& prev_match_pos->col <= cur_match_pos->col))) {
|
||||||
|
if (looped_around) {
|
||||||
|
found_new_match = FAIL;
|
||||||
|
} else {
|
||||||
|
looped_around = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*prev_match_pos = *cur_match_pos;
|
||||||
|
if (found_new_match == FAIL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when ADDING, the text before the cursor matches, skip it
|
||||||
|
if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
|
||||||
|
&& start_pos->lnum == cur_match_pos->lnum
|
||||||
|
&& start_pos->col == cur_match_pos->col) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char_u *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, false) + cur_match_pos->col;
|
||||||
|
int len;
|
||||||
|
if (ctrl_x_mode_line_or_eval()) {
|
||||||
|
if (compl_cont_status & CONT_ADDING) {
|
||||||
|
if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, false);
|
||||||
|
if (!p_paste) {
|
||||||
|
ptr = (char_u *)skipwhite((char *)ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = (int)STRLEN(ptr);
|
||||||
|
} else {
|
||||||
|
char_u *tmp_ptr = ptr;
|
||||||
|
|
||||||
|
if (compl_cont_status & CONT_ADDING) {
|
||||||
|
tmp_ptr += compl_length;
|
||||||
|
// Skip if already inside a word.
|
||||||
|
if (vim_iswordp(tmp_ptr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Find start of next word.
|
||||||
|
tmp_ptr = find_word_start(tmp_ptr);
|
||||||
|
}
|
||||||
|
// Find end of this word.
|
||||||
|
tmp_ptr = find_word_end(tmp_ptr);
|
||||||
|
len = (int)(tmp_ptr - ptr);
|
||||||
|
|
||||||
|
if ((compl_cont_status & CONT_ADDING) && len == compl_length) {
|
||||||
|
if (cur_match_pos->lnum < ins_buf->b_ml.ml_line_count) {
|
||||||
|
// Try next line, if any. the new word will be "join" as if the
|
||||||
|
// normal command "J" was used. IOSIZE is always greater than
|
||||||
|
// compl_length, so the next STRNCPY always works -- Acevedo
|
||||||
|
STRNCPY(IObuff, ptr, len); // NOLINT(runtime/printf)
|
||||||
|
ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, false);
|
||||||
|
tmp_ptr = ptr = (char_u *)skipwhite((char *)ptr);
|
||||||
|
// Find start of next word.
|
||||||
|
tmp_ptr = find_word_start(tmp_ptr);
|
||||||
|
// Find end of next word.
|
||||||
|
tmp_ptr = find_word_end(tmp_ptr);
|
||||||
|
if (tmp_ptr > ptr) {
|
||||||
|
if (*ptr != ')' && IObuff[len - 1] != TAB) {
|
||||||
|
if (IObuff[len - 1] != ' ') {
|
||||||
|
IObuff[len++] = ' ';
|
||||||
|
}
|
||||||
|
// IObuf =~ "\k.* ", thus len >= 2
|
||||||
|
if (p_js
|
||||||
|
&& (IObuff[len - 2] == '.'
|
||||||
|
|| IObuff[len - 2] == '?'
|
||||||
|
|| IObuff[len - 2] == '!')) {
|
||||||
|
IObuff[len++] = ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// copy as much as possible of the new word
|
||||||
|
if (tmp_ptr - ptr >= IOSIZE - len) {
|
||||||
|
tmp_ptr = ptr + IOSIZE - len - 1;
|
||||||
|
}
|
||||||
|
STRLCPY(IObuff + len, ptr, IOSIZE - len);
|
||||||
|
len += (int)(tmp_ptr - ptr);
|
||||||
|
cont_s_ipos = true;
|
||||||
|
}
|
||||||
|
IObuff[len] = NUL;
|
||||||
|
ptr = IObuff;
|
||||||
|
}
|
||||||
|
if (len == compl_length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ins_compl_add_infercase(ptr, len, p_ic,
|
||||||
|
ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
|
||||||
|
0, cont_s_ipos) != NOTDONE) {
|
||||||
|
found_new_match = OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p_scs = save_p_scs;
|
||||||
|
p_ws = save_p_ws;
|
||||||
|
|
||||||
|
return found_new_match;
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next expansion(s), using "compl_pattern".
|
/// Get the next expansion(s), using "compl_pattern".
|
||||||
/// The search starts at position "ini" in curbuf and in the direction
|
/// The search starts at position "ini" in curbuf and in the direction
|
||||||
/// compl_direction.
|
/// compl_direction.
|
||||||
@@ -2481,16 +2897,9 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
static buf_T *ins_buf = NULL; // buffer being scanned
|
static buf_T *ins_buf = NULL; // buffer being scanned
|
||||||
|
|
||||||
pos_T *pos;
|
pos_T *pos;
|
||||||
char **matches;
|
|
||||||
int save_p_scs;
|
|
||||||
bool save_p_ws;
|
|
||||||
int save_p_ic;
|
|
||||||
int i;
|
int i;
|
||||||
int num_matches;
|
|
||||||
int len;
|
|
||||||
int found_new_match;
|
int found_new_match;
|
||||||
int type = ctrl_x_mode;
|
int type = ctrl_x_mode;
|
||||||
char_u *ptr;
|
|
||||||
char_u *dict = NULL;
|
char_u *dict = NULL;
|
||||||
int dict_f = 0;
|
int dict_f = 0;
|
||||||
bool set_match_pos;
|
bool set_match_pos;
|
||||||
@@ -2524,89 +2933,14 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
// entries from 'complete' that look in loaded buffers.
|
// entries from 'complete' that look in loaded buffers.
|
||||||
if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
|
if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
|
||||||
&& (!compl_started || found_all)) {
|
&& (!compl_started || found_all)) {
|
||||||
found_all = false;
|
int status = process_next_cpt_value(&e_cpt, &type, &found_all,
|
||||||
while (*e_cpt == ',' || *e_cpt == ' ') {
|
&ins_buf, ini, &first_match_pos, &last_match_pos,
|
||||||
e_cpt++;
|
&set_match_pos, &dict, &dict_f);
|
||||||
}
|
if (status == INS_COMPL_CPT_END) {
|
||||||
if (*e_cpt == '.' && !curbuf->b_scanned) {
|
|
||||||
ins_buf = curbuf;
|
|
||||||
first_match_pos = *ini;
|
|
||||||
// Move the cursor back one character so that ^N can match the
|
|
||||||
// word immediately after the cursor.
|
|
||||||
if (ctrl_x_mode_normal() && dec(&first_match_pos) < 0) {
|
|
||||||
// Move the cursor to after the last character in the
|
|
||||||
// buffer, so that word at start of buffer is found
|
|
||||||
// correctly.
|
|
||||||
first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
|
|
||||||
first_match_pos.col = (colnr_T)STRLEN(ml_get(first_match_pos.lnum));
|
|
||||||
}
|
|
||||||
last_match_pos = first_match_pos;
|
|
||||||
type = 0;
|
|
||||||
|
|
||||||
// Remember the first match so that the loop stops when we
|
|
||||||
// wrap and come back there a second time.
|
|
||||||
set_match_pos = true;
|
|
||||||
} else if (vim_strchr("buwU", *e_cpt) != NULL
|
|
||||||
&& (ins_buf = ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
|
|
||||||
// Scan a buffer, but not the current one.
|
|
||||||
if (ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer
|
|
||||||
compl_started = true;
|
|
||||||
first_match_pos.col = last_match_pos.col = 0;
|
|
||||||
first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
|
|
||||||
last_match_pos.lnum = 0;
|
|
||||||
type = 0;
|
|
||||||
} else { // unloaded buffer, scan like dictionary
|
|
||||||
found_all = true;
|
|
||||||
if (ins_buf->b_fname == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
type = CTRL_X_DICTIONARY;
|
|
||||||
dict = (char_u *)ins_buf->b_fname;
|
|
||||||
dict_f = DICT_EXACT;
|
|
||||||
}
|
|
||||||
msg_hist_off = true; // reset in msg_trunc_attr()
|
|
||||||
vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
|
|
||||||
ins_buf->b_fname == NULL
|
|
||||||
? buf_spname(ins_buf)
|
|
||||||
: ins_buf->b_sfname == NULL
|
|
||||||
? ins_buf->b_fname
|
|
||||||
: ins_buf->b_sfname);
|
|
||||||
(void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
|
|
||||||
} else if (*e_cpt == NUL) {
|
|
||||||
break;
|
break;
|
||||||
} else {
|
}
|
||||||
if (ctrl_x_mode_line_or_eval()) {
|
if (status == INS_COMPL_CPT_CONT) {
|
||||||
type = -1;
|
continue;
|
||||||
} else if (*e_cpt == 'k' || *e_cpt == 's') {
|
|
||||||
if (*e_cpt == 'k') {
|
|
||||||
type = CTRL_X_DICTIONARY;
|
|
||||||
} else {
|
|
||||||
type = CTRL_X_THESAURUS;
|
|
||||||
}
|
|
||||||
if (*++e_cpt != ',' && *e_cpt != NUL) {
|
|
||||||
dict = (char_u *)e_cpt;
|
|
||||||
dict_f = DICT_FIRST;
|
|
||||||
}
|
|
||||||
} else if (*e_cpt == 'i') {
|
|
||||||
type = CTRL_X_PATH_PATTERNS;
|
|
||||||
} else if (*e_cpt == 'd') {
|
|
||||||
type = CTRL_X_PATH_DEFINES;
|
|
||||||
} else if (*e_cpt == ']' || *e_cpt == 't') {
|
|
||||||
msg_hist_off = true; // reset in msg_trunc_attr()
|
|
||||||
type = CTRL_X_TAGS;
|
|
||||||
vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags."));
|
|
||||||
(void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
|
|
||||||
} else {
|
|
||||||
type = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// in any case e_cpt is advanced to the next entry
|
|
||||||
(void)copy_option_part(&e_cpt, (char *)IObuff, IOSIZE, ",");
|
|
||||||
|
|
||||||
found_all = true;
|
|
||||||
if (type == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2621,80 +2955,25 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
break;
|
break;
|
||||||
case CTRL_X_PATH_PATTERNS:
|
case CTRL_X_PATH_PATTERNS:
|
||||||
case CTRL_X_PATH_DEFINES:
|
case CTRL_X_PATH_DEFINES:
|
||||||
find_pattern_in_path((char_u *)compl_pattern, compl_direction,
|
get_next_include_file_completion(type);
|
||||||
STRLEN(compl_pattern), false, false,
|
|
||||||
((type == CTRL_X_PATH_DEFINES
|
|
||||||
&& !(compl_cont_status & CONT_SOL))
|
|
||||||
? FIND_DEFINE
|
|
||||||
: FIND_ANY),
|
|
||||||
1L, ACTION_EXPAND, 1, MAXLNUM);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_X_DICTIONARY:
|
case CTRL_X_DICTIONARY:
|
||||||
case CTRL_X_THESAURUS:
|
case CTRL_X_THESAURUS:
|
||||||
if (thesaurus_func_complete(type)) {
|
get_next_dict_tsr_completion(type, &dict, dict_f);
|
||||||
expand_by_function(type, (char_u *)compl_pattern);
|
|
||||||
} else {
|
|
||||||
ins_compl_dictionaries(dict != NULL ? dict
|
|
||||||
: (type == CTRL_X_THESAURUS
|
|
||||||
? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
|
|
||||||
: (*curbuf->b_p_dict ==
|
|
||||||
NUL ? p_dict : curbuf->b_p_dict)),
|
|
||||||
(char_u *)compl_pattern,
|
|
||||||
dict != NULL ? dict_f : 0, type == CTRL_X_THESAURUS);
|
|
||||||
}
|
|
||||||
dict = NULL;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_X_TAGS:
|
case CTRL_X_TAGS:
|
||||||
// set p_ic according to p_ic, p_scs and pat for find_tags().
|
get_next_tag_completion();
|
||||||
save_p_ic = p_ic;
|
|
||||||
p_ic = ignorecase((char_u *)compl_pattern);
|
|
||||||
|
|
||||||
// Find up to TAG_MANY matches. Avoids that an enormous number
|
|
||||||
// of matches is found when compl_pattern is empty
|
|
||||||
g_tag_at_cursor = true;
|
|
||||||
if (find_tags((char_u *)compl_pattern, &num_matches, &matches,
|
|
||||||
TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
|
|
||||||
| (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0),
|
|
||||||
TAG_MANY, (char_u *)curbuf->b_ffname) == OK && num_matches > 0) {
|
|
||||||
ins_compl_add_matches(num_matches, matches, p_ic);
|
|
||||||
}
|
|
||||||
g_tag_at_cursor = false;
|
|
||||||
p_ic = save_p_ic;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_X_FILES:
|
case CTRL_X_FILES:
|
||||||
if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
|
get_next_filename_completion();
|
||||||
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
|
|
||||||
// May change home directory back to "~".
|
|
||||||
tilde_replace((char_u *)compl_pattern, num_matches, matches);
|
|
||||||
#ifdef BACKSLASH_IN_FILENAME
|
|
||||||
if (curbuf->b_p_csl[0] != NUL) {
|
|
||||||
for (int i = 0; i < num_matches; i++) {
|
|
||||||
char_u *ptr = matches[i];
|
|
||||||
while (*ptr != NUL) {
|
|
||||||
if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
|
|
||||||
*ptr = '/';
|
|
||||||
} else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') {
|
|
||||||
*ptr = '\\';
|
|
||||||
}
|
|
||||||
ptr += utfc_ptr2len(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_X_CMDLINE:
|
case CTRL_X_CMDLINE:
|
||||||
case CTRL_X_CMDLINE_CTRL_X:
|
case CTRL_X_CMDLINE_CTRL_X:
|
||||||
if (expand_cmdline(&compl_xp, (char_u *)compl_pattern,
|
get_next_cmdline_completion();
|
||||||
(int)STRLEN(compl_pattern),
|
|
||||||
&num_matches, &matches) == EXPAND_OK) {
|
|
||||||
ins_compl_add_matches(num_matches, matches, false);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_X_FUNCTION:
|
case CTRL_X_FUNCTION:
|
||||||
@@ -2703,172 +2982,16 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_X_SPELL:
|
case CTRL_X_SPELL:
|
||||||
num_matches = expand_spelling(first_match_pos.lnum,
|
get_next_spell_completion(first_match_pos.lnum);
|
||||||
(char_u *)compl_pattern, &matches);
|
|
||||||
if (num_matches > 0) {
|
|
||||||
ins_compl_add_matches(num_matches, matches, p_ic);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: // normal ^P/^N and ^X^L
|
default: // normal ^P/^N and ^X^L
|
||||||
// If 'infercase' is set, don't use 'smartcase' here
|
found_new_match = get_next_default_completion(ins_buf, ini, pos, &prev_pos,
|
||||||
save_p_scs = p_scs;
|
&set_match_pos, &first_match_pos,
|
||||||
assert(ins_buf);
|
&last_match_pos, (*e_cpt == '.'));
|
||||||
if (ins_buf->b_p_inf) {
|
if (found_new_match == FAIL && ins_buf == curbuf) {
|
||||||
p_scs = false;
|
found_all = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffers other than curbuf are scanned from the beginning or the
|
|
||||||
// end but never from the middle, thus setting nowrapscan in this
|
|
||||||
// buffers is a good idea, on the other hand, we always set
|
|
||||||
// wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
|
|
||||||
save_p_ws = p_ws;
|
|
||||||
if (ins_buf != curbuf) {
|
|
||||||
p_ws = false;
|
|
||||||
} else if (*e_cpt == '.') {
|
|
||||||
p_ws = true;
|
|
||||||
}
|
|
||||||
bool looped_around = false;
|
|
||||||
for (;;) {
|
|
||||||
bool cont_s_ipos = false;
|
|
||||||
|
|
||||||
msg_silent++; // Don't want messages for wrapscan.
|
|
||||||
// ctrl_x_mode_line_or_eval() || word-wise search that
|
|
||||||
// has added a word that was at the beginning of the line.
|
|
||||||
if (ctrl_x_mode_line_or_eval()
|
|
||||||
|| (compl_cont_status & CONT_SOL)) {
|
|
||||||
found_new_match = search_for_exact_line(ins_buf, pos,
|
|
||||||
compl_direction,
|
|
||||||
(char_u *)compl_pattern);
|
|
||||||
} else {
|
|
||||||
found_new_match = searchit(NULL, ins_buf, pos, NULL,
|
|
||||||
compl_direction,
|
|
||||||
(char_u *)compl_pattern, 1L,
|
|
||||||
SEARCH_KEEP + SEARCH_NFMSG,
|
|
||||||
RE_LAST, NULL);
|
|
||||||
}
|
|
||||||
msg_silent--;
|
|
||||||
if (!compl_started || set_match_pos) {
|
|
||||||
// set "compl_started" even on fail
|
|
||||||
compl_started = true;
|
|
||||||
first_match_pos = *pos;
|
|
||||||
last_match_pos = *pos;
|
|
||||||
set_match_pos = false;
|
|
||||||
} else if (first_match_pos.lnum == last_match_pos.lnum
|
|
||||||
&& first_match_pos.col == last_match_pos.col) {
|
|
||||||
found_new_match = FAIL;
|
|
||||||
} else if ((compl_direction == FORWARD)
|
|
||||||
&& (prev_pos.lnum > pos->lnum
|
|
||||||
|| (prev_pos.lnum == pos->lnum
|
|
||||||
&& prev_pos.col >= pos->col))) {
|
|
||||||
if (looped_around) {
|
|
||||||
found_new_match = FAIL;
|
|
||||||
} else {
|
|
||||||
looped_around = true;
|
|
||||||
}
|
|
||||||
} else if ((compl_direction != FORWARD)
|
|
||||||
&& (prev_pos.lnum < pos->lnum
|
|
||||||
|| (prev_pos.lnum == pos->lnum
|
|
||||||
&& prev_pos.col <= pos->col))) {
|
|
||||||
if (looped_around) {
|
|
||||||
found_new_match = FAIL;
|
|
||||||
} else {
|
|
||||||
looped_around = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prev_pos = *pos;
|
|
||||||
if (found_new_match == FAIL) {
|
|
||||||
if (ins_buf == curbuf) {
|
|
||||||
found_all = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// when ADDING, the text before the cursor matches, skip it
|
|
||||||
if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
|
|
||||||
&& ini->lnum == pos->lnum
|
|
||||||
&& ini->col == pos->col) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ptr = ml_get_buf(ins_buf, pos->lnum, false) + pos->col;
|
|
||||||
if (ctrl_x_mode_line_or_eval()) {
|
|
||||||
if (compl_cont_status & CONT_ADDING) {
|
|
||||||
if (pos->lnum >= ins_buf->b_ml.ml_line_count) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
|
|
||||||
if (!p_paste) {
|
|
||||||
ptr = (char_u *)skipwhite((char *)ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
len = (int)STRLEN(ptr);
|
|
||||||
} else {
|
|
||||||
char_u *tmp_ptr = ptr;
|
|
||||||
|
|
||||||
if (compl_cont_status & CONT_ADDING) {
|
|
||||||
tmp_ptr += compl_length;
|
|
||||||
// Skip if already inside a word.
|
|
||||||
if (vim_iswordp(tmp_ptr)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Find start of next word.
|
|
||||||
tmp_ptr = find_word_start(tmp_ptr);
|
|
||||||
}
|
|
||||||
// Find end of this word.
|
|
||||||
tmp_ptr = find_word_end(tmp_ptr);
|
|
||||||
len = (int)(tmp_ptr - ptr);
|
|
||||||
|
|
||||||
if ((compl_cont_status & CONT_ADDING)
|
|
||||||
&& len == compl_length) {
|
|
||||||
if (pos->lnum < ins_buf->b_ml.ml_line_count) {
|
|
||||||
// Try next line, if any. the new word will be "join" as if the
|
|
||||||
// normal command "J" was used. IOSIZE is always greater than
|
|
||||||
// compl_length, so the next STRNCPY always works -- Acevedo
|
|
||||||
STRNCPY(IObuff, ptr, len); // NOLINT(runtime/printf)
|
|
||||||
ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
|
|
||||||
tmp_ptr = ptr = (char_u *)skipwhite((char *)ptr);
|
|
||||||
// Find start of next word.
|
|
||||||
tmp_ptr = find_word_start(tmp_ptr);
|
|
||||||
// Find end of next word.
|
|
||||||
tmp_ptr = find_word_end(tmp_ptr);
|
|
||||||
if (tmp_ptr > ptr) {
|
|
||||||
if (*ptr != ')' && IObuff[len - 1] != TAB) {
|
|
||||||
if (IObuff[len - 1] != ' ') {
|
|
||||||
IObuff[len++] = ' ';
|
|
||||||
}
|
|
||||||
// IObuf =~ "\k.* ", thus len >= 2
|
|
||||||
if (p_js
|
|
||||||
&& (IObuff[len - 2] == '.'
|
|
||||||
|| IObuff[len - 2] == '?'
|
|
||||||
|| IObuff[len - 2] == '!')) {
|
|
||||||
IObuff[len++] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// copy as much as possible of the new word
|
|
||||||
if (tmp_ptr - ptr >= IOSIZE - len) {
|
|
||||||
tmp_ptr = ptr + IOSIZE - len - 1;
|
|
||||||
}
|
|
||||||
STRLCPY(IObuff + len, ptr, IOSIZE - len);
|
|
||||||
len += (int)(tmp_ptr - ptr);
|
|
||||||
cont_s_ipos = true;
|
|
||||||
}
|
|
||||||
IObuff[len] = NUL;
|
|
||||||
ptr = IObuff;
|
|
||||||
}
|
|
||||||
if (len == compl_length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ins_compl_add_infercase(ptr, len, p_ic,
|
|
||||||
ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
|
|
||||||
0, cont_s_ipos) != NOTDONE) {
|
|
||||||
found_new_match = OK;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p_scs = save_p_scs;
|
|
||||||
p_ws = save_p_ws;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if compl_curr_match has changed, (e.g. other type of
|
// check if compl_curr_match has changed, (e.g. other type of
|
||||||
|
@@ -44,11 +44,11 @@ func Test_ins_complete()
|
|||||||
exe "normal o\<C-X>\<C-P>\<C-P>\<C-X>\<C-X>\<C-N>\<C-X>\<C-N>\<C-N>"
|
exe "normal o\<C-X>\<C-P>\<C-P>\<C-X>\<C-X>\<C-N>\<C-X>\<C-N>\<C-N>"
|
||||||
call assert_equal('run1 run2', getline('.'))
|
call assert_equal('run1 run2', getline('.'))
|
||||||
|
|
||||||
set cpt=.,w,i
|
set cpt=.,\ ,w,i
|
||||||
" i-add-expands and switches to local
|
" i-add-expands and switches to local
|
||||||
exe "normal OM\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-X>\<C-X>\<C-P>"
|
exe "normal OM\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-X>\<C-X>\<C-P>"
|
||||||
call assert_equal("Makefile\tto\trun3", getline('.'))
|
call assert_equal("Makefile\tto\trun3", getline('.'))
|
||||||
" add-expands lines (it would end in an empty line if it didn't ignored
|
" add-expands lines (it would end in an empty line if it didn't ignore
|
||||||
" itself)
|
" itself)
|
||||||
exe "normal o\<C-X>\<C-L>\<C-X>\<C-L>\<C-P>\<C-P>"
|
exe "normal o\<C-X>\<C-L>\<C-X>\<C-L>\<C-P>\<C-P>"
|
||||||
call assert_equal("Makefile\tto\trun3", getline('.'))
|
call assert_equal("Makefile\tto\trun3", getline('.'))
|
||||||
@@ -721,6 +721,17 @@ func Test_complete_across_line()
|
|||||||
close!
|
close!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for completing words with a '.' at the end of a word.
|
||||||
|
func Test_complete_joinspaces()
|
||||||
|
new
|
||||||
|
call setline(1, ['one two.', 'three. four'])
|
||||||
|
set joinspaces
|
||||||
|
exe "normal Goon\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
|
||||||
|
call assert_equal("one two. three. four", getline(3))
|
||||||
|
set joinspaces&
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Test for using CTRL-L to add one character when completing matching
|
" Test for using CTRL-L to add one character when completing matching
|
||||||
func Test_complete_add_onechar()
|
func Test_complete_add_onechar()
|
||||||
new
|
new
|
||||||
@@ -741,6 +752,39 @@ func Test_complete_add_onechar()
|
|||||||
close!
|
close!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for using CTRL-X CTRL-L to complete whole lines lines
|
||||||
|
func Test_complete_wholeline()
|
||||||
|
new
|
||||||
|
" complete one-line
|
||||||
|
call setline(1, ['a1', 'a2'])
|
||||||
|
exe "normal ggoa\<C-X>\<C-L>"
|
||||||
|
call assert_equal(['a1', 'a1', 'a2'], getline(1, '$'))
|
||||||
|
" go to the next match (wrapping around the buffer)
|
||||||
|
exe "normal 2GCa\<C-X>\<C-L>\<C-N>"
|
||||||
|
call assert_equal(['a1', 'a', 'a2'], getline(1, '$'))
|
||||||
|
" go to the next match
|
||||||
|
exe "normal 2GCa\<C-X>\<C-L>\<C-N>\<C-N>"
|
||||||
|
call assert_equal(['a1', 'a2', 'a2'], getline(1, '$'))
|
||||||
|
exe "normal 2GCa\<C-X>\<C-L>\<C-N>\<C-N>\<C-N>"
|
||||||
|
call assert_equal(['a1', 'a1', 'a2'], getline(1, '$'))
|
||||||
|
" repeat the test using CTRL-L
|
||||||
|
" go to the next match (wrapping around the buffer)
|
||||||
|
exe "normal 2GCa\<C-X>\<C-L>\<C-L>"
|
||||||
|
call assert_equal(['a1', 'a2', 'a2'], getline(1, '$'))
|
||||||
|
" go to the next match
|
||||||
|
exe "normal 2GCa\<C-X>\<C-L>\<C-L>\<C-L>"
|
||||||
|
call assert_equal(['a1', 'a', 'a2'], getline(1, '$'))
|
||||||
|
exe "normal 2GCa\<C-X>\<C-L>\<C-L>\<C-L>\<C-L>"
|
||||||
|
call assert_equal(['a1', 'a1', 'a2'], getline(1, '$'))
|
||||||
|
%d
|
||||||
|
" use CTRL-X CTRL-L to add one more line
|
||||||
|
call setline(1, ['a1', 'b1'])
|
||||||
|
setlocal complete=.
|
||||||
|
exe "normal ggOa\<C-X>\<C-L>\<C-X>\<C-L>\<C-X>\<C-L>"
|
||||||
|
call assert_equal(['a1', 'b1', '', 'a1', 'b1'], getline(1, '$'))
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Test insert completion with 'cindent' (adjust the indent)
|
" Test insert completion with 'cindent' (adjust the indent)
|
||||||
func Test_complete_with_cindent()
|
func Test_complete_with_cindent()
|
||||||
new
|
new
|
||||||
|
Reference in New Issue
Block a user