mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
Compare commits
11 Commits
10e87249b7
...
d31ff7bfcd
Author | SHA1 | Date | |
---|---|---|---|
|
d31ff7bfcd | ||
|
160cbd0ef4 | ||
|
3db3947b0e | ||
|
28fa71d743 | ||
|
36fcc1d9ae | ||
|
b53ba9d9a7 | ||
|
af199f9f02 | ||
|
d75a36bc52 | ||
|
e340109bef | ||
|
2a79de0a6f | ||
|
46d89ff9f8 |
@ -1566,10 +1566,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
fuzzy Enable |fuzzy-matching| for completion candidates. This
|
fuzzy Enable |fuzzy-matching| for completion candidates. This
|
||||||
allows for more flexible and intuitive matching, where
|
allows for more flexible and intuitive matching, where
|
||||||
characters can be skipped and matches can be found even
|
characters can be skipped and matches can be found even
|
||||||
if the exact sequence is not typed. Only makes a
|
if the exact sequence is not typed.
|
||||||
difference how completion candidates are reduced from the
|
|
||||||
list of alternatives, but not how the candidates are
|
|
||||||
collected (using different completion types).
|
|
||||||
|
|
||||||
*'completeslash'* *'csl'*
|
*'completeslash'* *'csl'*
|
||||||
'completeslash' 'csl' string (default "")
|
'completeslash' 'csl' string (default "")
|
||||||
|
5
runtime/lua/vim/_meta/options.lua
generated
5
runtime/lua/vim/_meta/options.lua
generated
@ -1093,10 +1093,7 @@ vim.go.cia = vim.go.completeitemalign
|
|||||||
--- fuzzy Enable `fuzzy-matching` for completion candidates. This
|
--- fuzzy Enable `fuzzy-matching` for completion candidates. This
|
||||||
--- allows for more flexible and intuitive matching, where
|
--- allows for more flexible and intuitive matching, where
|
||||||
--- characters can be skipped and matches can be found even
|
--- characters can be skipped and matches can be found even
|
||||||
--- if the exact sequence is not typed. Only makes a
|
--- if the exact sequence is not typed.
|
||||||
--- difference how completion candidates are reduced from the
|
|
||||||
--- list of alternatives, but not how the candidates are
|
|
||||||
--- collected (using different completion types).
|
|
||||||
---
|
---
|
||||||
--- @type string
|
--- @type string
|
||||||
vim.o.completeopt = "menu,preview"
|
vim.o.completeopt = "menu,preview"
|
||||||
|
@ -283,6 +283,8 @@ static size_t spell_bad_len = 0; // length of located bad word
|
|||||||
|
|
||||||
static int compl_selected_item = -1;
|
static int compl_selected_item = -1;
|
||||||
|
|
||||||
|
static int *compl_fuzzy_scores;
|
||||||
|
|
||||||
// "compl_match_array" points the currently displayed list of entries in the
|
// "compl_match_array" points the currently displayed list of entries in the
|
||||||
// popup menu. It is NULL when there is no popup menu.
|
// popup menu. It is NULL when there is no popup menu.
|
||||||
static pumitem_T *compl_match_array = NULL;
|
static pumitem_T *compl_match_array = NULL;
|
||||||
@ -3008,7 +3010,7 @@ enum {
|
|||||||
/// the "st->e_cpt" option value and process the next matching source.
|
/// 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, bool in_fuzzy)
|
||||||
{
|
{
|
||||||
int compl_type = -1;
|
int compl_type = -1;
|
||||||
int status = INS_COMPL_CPT_OK;
|
int status = INS_COMPL_CPT_OK;
|
||||||
@ -3024,7 +3026,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
|
|||||||
st->first_match_pos = *start_match_pos;
|
st->first_match_pos = *start_match_pos;
|
||||||
// Move the cursor back one character so that ^N can match the
|
// Move the cursor back one character so that ^N can match the
|
||||||
// word immediately after the cursor.
|
// word immediately after the cursor.
|
||||||
if (ctrl_x_mode_normal() && dec(&st->first_match_pos) < 0) {
|
if (ctrl_x_mode_normal() && (!in_fuzzy && dec(&st->first_match_pos) < 0)) {
|
||||||
// Move the cursor to after the last character in the
|
// Move the cursor to after the last character in the
|
||||||
// buffer, so that word at start of buffer is found
|
// buffer, so that word at start of buffer is found
|
||||||
// correctly.
|
// correctly.
|
||||||
@ -3162,11 +3164,75 @@ static void get_next_tag_completion(void)
|
|||||||
p_ic = save_p_ic;
|
p_ic = save_p_ic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compare function for qsort
|
||||||
|
static int compare_scores(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
int idx_a = *(const int *)a;
|
||||||
|
int idx_b = *(const int *)b;
|
||||||
|
int score_a = compl_fuzzy_scores[idx_a];
|
||||||
|
int score_b = compl_fuzzy_scores[idx_b];
|
||||||
|
return score_a == score_b ? (idx_a == idx_b ? 0 : (idx_a < idx_b ? -1 : 1))
|
||||||
|
: (score_a > score_b ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next set of filename matching "compl_pattern".
|
/// Get the next set of filename matching "compl_pattern".
|
||||||
static void get_next_filename_completion(void)
|
static void get_next_filename_completion(void)
|
||||||
{
|
{
|
||||||
char **matches;
|
char **matches;
|
||||||
int num_matches;
|
int num_matches;
|
||||||
|
char *leader = ins_compl_leader();
|
||||||
|
size_t leader_len = strlen(leader);
|
||||||
|
bool in_fuzzy = ((get_cot_flags() & kOptCotFlagFuzzy) != 0 && leader_len > 0);
|
||||||
|
|
||||||
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
|
char pathsep = (curbuf->b_p_csl[0] == 's')
|
||||||
|
? '/' : (curbuf->b_p_csl[0] == 'b') ? '\\' : PATHSEP;
|
||||||
|
#else
|
||||||
|
char pathsep = PATHSEP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (in_fuzzy) {
|
||||||
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
|
if (curbuf->b_p_csl[0] == 's') {
|
||||||
|
for (size_t i = 0; i < leader_len; i++) {
|
||||||
|
if (leader[i] == '\\') {
|
||||||
|
leader[i] = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (curbuf->b_p_csl[0] == 'b') {
|
||||||
|
for (size_t i = 0; i < leader_len; i++) {
|
||||||
|
if (leader[i] == '/') {
|
||||||
|
leader[i] = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
char *last_sep = strrchr(leader, pathsep);
|
||||||
|
if (last_sep == NULL) {
|
||||||
|
// No path separator or separator is the last character,
|
||||||
|
// fuzzy match the whole leader
|
||||||
|
xfree(compl_pattern);
|
||||||
|
compl_pattern = xstrdup("*");
|
||||||
|
compl_patternlen = strlen(compl_pattern);
|
||||||
|
} else if (*(last_sep + 1) == NUL) {
|
||||||
|
in_fuzzy = false;
|
||||||
|
} else {
|
||||||
|
// Split leader into path and file parts
|
||||||
|
size_t path_len = (size_t)(last_sep - leader) + 1;
|
||||||
|
size_t path_with_wildcard_len = path_len + 2;
|
||||||
|
char *path_with_wildcard = xmalloc(path_with_wildcard_len);
|
||||||
|
xmemcpyz(path_with_wildcard, leader, path_len);
|
||||||
|
xstrlcat(path_with_wildcard, "*", path_with_wildcard_len);
|
||||||
|
xfree(compl_pattern);
|
||||||
|
compl_pattern = path_with_wildcard;
|
||||||
|
compl_patternlen = strlen(compl_pattern);
|
||||||
|
|
||||||
|
// Move leader to the file part
|
||||||
|
leader = last_sep + 1;
|
||||||
|
leader_len = strlen(leader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
|
if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
|
||||||
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) {
|
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) {
|
||||||
return;
|
return;
|
||||||
@ -3189,7 +3255,46 @@ static void get_next_filename_completion(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
|
|
||||||
|
if (in_fuzzy) {
|
||||||
|
garray_T fuzzy_indices;
|
||||||
|
ga_init(&fuzzy_indices, sizeof(int), 10);
|
||||||
|
compl_fuzzy_scores = (int *)xmalloc(sizeof(int) * (size_t)num_matches);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_matches; i++) {
|
||||||
|
char *ptr = matches[i];
|
||||||
|
int score = fuzzy_match_str(ptr, leader);
|
||||||
|
if (score > 0) {
|
||||||
|
GA_APPEND(int, &fuzzy_indices, i);
|
||||||
|
compl_fuzzy_scores[i] = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent qsort from deref NULL pointer
|
||||||
|
if (fuzzy_indices.ga_len > 0) {
|
||||||
|
int *fuzzy_indices_data = (int *)fuzzy_indices.ga_data;
|
||||||
|
qsort(fuzzy_indices_data, (size_t)fuzzy_indices.ga_len, sizeof(int), compare_scores);
|
||||||
|
|
||||||
|
char **sorted_matches = (char **)xmalloc(sizeof(char *) * (size_t)fuzzy_indices.ga_len);
|
||||||
|
for (int i = 0; i < fuzzy_indices.ga_len; i++) {
|
||||||
|
sorted_matches[i] = xstrdup(matches[fuzzy_indices_data[i]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeWild(num_matches, matches);
|
||||||
|
matches = sorted_matches;
|
||||||
|
num_matches = fuzzy_indices.ga_len;
|
||||||
|
} else if (leader_len > 0) {
|
||||||
|
FreeWild(num_matches, matches);
|
||||||
|
num_matches = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree(compl_fuzzy_scores);
|
||||||
|
ga_clear(&fuzzy_indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_matches > 0) {
|
||||||
|
ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next set of command-line completions matching "compl_pattern".
|
/// Get the next set of command-line completions matching "compl_pattern".
|
||||||
@ -3310,6 +3415,11 @@ static char *ins_compl_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_po
|
|||||||
/// @return OK if a new next match is found, otherwise FAIL.
|
/// @return OK if a new next match is found, otherwise FAIL.
|
||||||
static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
|
static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
|
||||||
{
|
{
|
||||||
|
char *ptr = NULL;
|
||||||
|
int len = 0;
|
||||||
|
bool in_fuzzy = (get_cot_flags() & kOptCotFlagFuzzy) != 0 && compl_length > 0;
|
||||||
|
char *leader = ins_compl_leader();
|
||||||
|
|
||||||
// If 'infercase' is set, don't use 'smartcase' here
|
// If 'infercase' is set, don't use 'smartcase' here
|
||||||
const int save_p_scs = p_scs;
|
const int save_p_scs = p_scs;
|
||||||
assert(st->ins_buf);
|
assert(st->ins_buf);
|
||||||
@ -3324,7 +3434,7 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
|
|||||||
const int save_p_ws = p_ws;
|
const int save_p_ws = p_ws;
|
||||||
if (st->ins_buf != curbuf) {
|
if (st->ins_buf != curbuf) {
|
||||||
p_ws = false;
|
p_ws = false;
|
||||||
} else if (*st->e_cpt == '.') {
|
} else if (*st->e_cpt == '.' && !in_fuzzy) {
|
||||||
p_ws = true;
|
p_ws = true;
|
||||||
}
|
}
|
||||||
bool looped_around = false;
|
bool looped_around = false;
|
||||||
@ -3335,9 +3445,14 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
|
|||||||
msg_silent++; // Don't want messages for wrapscan.
|
msg_silent++; // Don't want messages for wrapscan.
|
||||||
// ctrl_x_mode_line_or_eval() || word-wise search that
|
// ctrl_x_mode_line_or_eval() || word-wise search that
|
||||||
// has added a word that was at the beginning of the line.
|
// has added a word that was at the beginning of the line.
|
||||||
if (ctrl_x_mode_line_or_eval() || (compl_cont_status & CONT_SOL)) {
|
if ((ctrl_x_mode_whole_line() && !in_fuzzy) || ctrl_x_mode_eval()
|
||||||
|
|| (compl_cont_status & CONT_SOL)) {
|
||||||
found_new_match = search_for_exact_line(st->ins_buf, st->cur_match_pos,
|
found_new_match = search_for_exact_line(st->ins_buf, st->cur_match_pos,
|
||||||
compl_direction, compl_pattern);
|
compl_direction, compl_pattern);
|
||||||
|
} else if (in_fuzzy) {
|
||||||
|
found_new_match = search_for_fuzzy_match(st->ins_buf,
|
||||||
|
st->cur_match_pos, leader, compl_direction,
|
||||||
|
start_pos, &len, &ptr, ctrl_x_mode_whole_line());
|
||||||
} else {
|
} else {
|
||||||
found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
|
found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
|
||||||
NULL, compl_direction, compl_pattern, compl_patternlen,
|
NULL, compl_direction, compl_pattern, compl_patternlen,
|
||||||
@ -3383,12 +3498,15 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
|
|||||||
&& start_pos->col == st->cur_match_pos->col) {
|
&& start_pos->col == st->cur_match_pos->col) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int len;
|
|
||||||
char *ptr = ins_compl_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
|
if (!in_fuzzy) {
|
||||||
&len, &cont_s_ipos);
|
ptr = ins_compl_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
|
||||||
|
&len, &cont_s_ipos);
|
||||||
|
}
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ins_compl_add_infercase(ptr, len, p_ic,
|
if (ins_compl_add_infercase(ptr, len, p_ic,
|
||||||
st->ins_buf == curbuf ? NULL : st->ins_buf->b_sfname,
|
st->ins_buf == curbuf ? NULL : st->ins_buf->b_sfname,
|
||||||
0, cont_s_ipos) != NOTDONE) {
|
0, cont_s_ipos) != NOTDONE) {
|
||||||
@ -3489,6 +3607,7 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
static bool st_cleared = false;
|
static bool st_cleared = false;
|
||||||
int found_new_match;
|
int found_new_match;
|
||||||
int type = ctrl_x_mode;
|
int type = ctrl_x_mode;
|
||||||
|
bool in_fuzzy = (get_cot_flags() & kOptCotFlagFuzzy) != 0;
|
||||||
|
|
||||||
assert(curbuf != NULL);
|
assert(curbuf != NULL);
|
||||||
|
|
||||||
@ -3525,7 +3644,7 @@ 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 || st.found_all)) {
|
&& (!compl_started || st.found_all)) {
|
||||||
int status = process_next_cpt_value(&st, &type, ini);
|
int status = process_next_cpt_value(&st, &type, ini, in_fuzzy);
|
||||||
if (status == INS_COMPL_CPT_END) {
|
if (status == INS_COMPL_CPT_END) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4483,6 +4602,7 @@ static int ins_compl_start(void)
|
|||||||
line = ml_get(curwin->w_cursor.lnum);
|
line = ml_get(curwin->w_cursor.lnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool in_fuzzy = get_cot_flags() & kOptCotFlagFuzzy;
|
||||||
if (compl_status_adding()) {
|
if (compl_status_adding()) {
|
||||||
edit_submode_pre = _(" Adding");
|
edit_submode_pre = _(" Adding");
|
||||||
if (ctrl_x_mode_line_or_eval()) {
|
if (ctrl_x_mode_line_or_eval()) {
|
||||||
@ -4496,6 +4616,9 @@ static int ins_compl_start(void)
|
|||||||
curbuf->b_p_com = old;
|
curbuf->b_p_com = old;
|
||||||
compl_length = 0;
|
compl_length = 0;
|
||||||
compl_col = curwin->w_cursor.col;
|
compl_col = curwin->w_cursor.col;
|
||||||
|
} else if (ctrl_x_mode_normal() && in_fuzzy) {
|
||||||
|
compl_startpos = curwin->w_cursor;
|
||||||
|
compl_cont_status &= CONT_S_IPOS;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
edit_submode_pre = NULL;
|
edit_submode_pre = NULL;
|
||||||
|
@ -1537,10 +1537,7 @@ return {
|
|||||||
fuzzy Enable |fuzzy-matching| for completion candidates. This
|
fuzzy Enable |fuzzy-matching| for completion candidates. This
|
||||||
allows for more flexible and intuitive matching, where
|
allows for more flexible and intuitive matching, where
|
||||||
characters can be skipped and matches can be found even
|
characters can be skipped and matches can be found even
|
||||||
if the exact sequence is not typed. Only makes a
|
if the exact sequence is not typed.
|
||||||
difference how completion candidates are reduced from the
|
|
||||||
list of alternatives, but not how the candidates are
|
|
||||||
collected (using different completion types).
|
|
||||||
]=],
|
]=],
|
||||||
expand_cb = 'expand_set_completeopt',
|
expand_cb = 'expand_set_completeopt',
|
||||||
full_name = 'completeopt',
|
full_name = 'completeopt',
|
||||||
|
@ -3564,6 +3564,166 @@ garray_T *fuzzy_match_str_with_pos(char *const str, const char *const pat)
|
|||||||
return match_positions;
|
return match_positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function searches for a fuzzy match of the pattern `pat` within the
|
||||||
|
/// line pointed to by `*ptr`. It splits the line into words, performs fuzzy
|
||||||
|
/// matching on each word, and returns the length and position of the first
|
||||||
|
/// matched word.
|
||||||
|
static bool fuzzy_match_str_in_line(char **ptr, char *pat, int *len, pos_T *current_pos)
|
||||||
|
{
|
||||||
|
char *str = *ptr;
|
||||||
|
char *strBegin = str;
|
||||||
|
char *end = NULL;
|
||||||
|
char *start = NULL;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (str == NULL || pat == NULL) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*str != NUL) {
|
||||||
|
// Skip non-word characters
|
||||||
|
start = find_word_start(str);
|
||||||
|
if (*start == NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
end = find_word_end(start);
|
||||||
|
|
||||||
|
// Extract the word from start to end
|
||||||
|
char save_end = *end;
|
||||||
|
*end = NUL;
|
||||||
|
|
||||||
|
// Perform fuzzy match
|
||||||
|
int result = fuzzy_match_str(start, pat);
|
||||||
|
*end = save_end;
|
||||||
|
|
||||||
|
if (result > 0) {
|
||||||
|
*len = (int)(end - start);
|
||||||
|
current_pos->col += (int)(end - strBegin);
|
||||||
|
found = true;
|
||||||
|
*ptr = start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the end of the current word for the next iteration
|
||||||
|
str = end;
|
||||||
|
// Ensure we continue searching after the current word
|
||||||
|
while (*str != NUL && !vim_iswordp(str)) {
|
||||||
|
MB_PTR_ADV(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Search for the next fuzzy match in the specified buffer.
|
||||||
|
/// This function attempts to find the next occurrence of the given pattern
|
||||||
|
/// in the buffer, starting from the current position. It handles line wrapping
|
||||||
|
/// and direction of search.
|
||||||
|
///
|
||||||
|
/// Return true if a match is found, otherwise false.
|
||||||
|
bool search_for_fuzzy_match(buf_T *buf, pos_T *pos, char *pattern, int dir, pos_T *start_pos,
|
||||||
|
int *len, char **ptr, bool whole_line)
|
||||||
|
{
|
||||||
|
pos_T current_pos = *pos;
|
||||||
|
pos_T circly_end;
|
||||||
|
bool found_new_match = false;
|
||||||
|
bool looped_around = false;
|
||||||
|
char *next_word_end = NULL;
|
||||||
|
char *match_word = NULL;
|
||||||
|
|
||||||
|
if (whole_line) {
|
||||||
|
current_pos.lnum += dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf == curbuf) {
|
||||||
|
circly_end = *start_pos;
|
||||||
|
} else {
|
||||||
|
circly_end.lnum = buf->b_ml.ml_line_count;
|
||||||
|
circly_end.col = 0;
|
||||||
|
circly_end.coladd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
// Check if looped around and back to start position
|
||||||
|
if (looped_around && equalpos(current_pos, circly_end)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure current_pos is valid
|
||||||
|
if (current_pos.lnum >= 1 && current_pos.lnum <= buf->b_ml.ml_line_count) {
|
||||||
|
// Get the current line buffer
|
||||||
|
*ptr = ml_get_buf(buf, current_pos.lnum);
|
||||||
|
// If ptr is end of line is reached, move to next line
|
||||||
|
// or previous line based on direction
|
||||||
|
if (**ptr != NUL) {
|
||||||
|
if (!whole_line) {
|
||||||
|
*ptr += current_pos.col;
|
||||||
|
// Try to find a fuzzy match in the current line starting from current position
|
||||||
|
found_new_match = fuzzy_match_str_in_line(ptr, pattern, len, ¤t_pos);
|
||||||
|
if (found_new_match) {
|
||||||
|
if (ctrl_x_mode_normal()) {
|
||||||
|
match_word = xstrnsave(*ptr, (size_t)(*len));
|
||||||
|
if (strcmp(match_word, pattern) == 0) {
|
||||||
|
next_word_end = find_word_start(*ptr + *len);
|
||||||
|
if (*next_word_end != NUL && *next_word_end != NL) {
|
||||||
|
// Find end of the word.
|
||||||
|
while (*next_word_end != NUL) {
|
||||||
|
int l = utfc_ptr2len(next_word_end);
|
||||||
|
if (l < 2 && !vim_iswordc(*next_word_end)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_word_end += l;
|
||||||
|
}
|
||||||
|
} else if (looped_around) {
|
||||||
|
found_new_match = false;
|
||||||
|
}
|
||||||
|
*len = (int)(next_word_end - *ptr);
|
||||||
|
current_pos.col = *len;
|
||||||
|
}
|
||||||
|
xfree(match_word);
|
||||||
|
}
|
||||||
|
*pos = current_pos;
|
||||||
|
break;
|
||||||
|
} else if (looped_around && current_pos.lnum == circly_end.lnum) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fuzzy_match_str(*ptr, pattern) > 0) {
|
||||||
|
found_new_match = true;
|
||||||
|
*pos = current_pos;
|
||||||
|
*len = (int)strlen(*ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to the next line or previous line based on direction
|
||||||
|
if (dir == FORWARD) {
|
||||||
|
if (++current_pos.lnum > buf->b_ml.ml_line_count) {
|
||||||
|
if (p_ws) {
|
||||||
|
current_pos.lnum = 1;
|
||||||
|
looped_around = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (--current_pos.lnum < 1) {
|
||||||
|
if (p_ws) {
|
||||||
|
current_pos.lnum = buf->b_ml.ml_line_count;
|
||||||
|
looped_around = true;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_pos.col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return found_new_match;
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy a list of fuzzy matches into a string list after sorting the matches by
|
/// Copy a list of fuzzy matches into a string list after sorting the matches by
|
||||||
/// the fuzzy score. Frees the memory allocated for "fuzmatch".
|
/// the fuzzy score. Frees the memory allocated for "fuzmatch".
|
||||||
void fuzzymatches_to_strmatches(fuzmatch_str_T *const fuzmatch, char ***const matches,
|
void fuzzymatches_to_strmatches(fuzmatch_str_T *const fuzmatch, char ***const matches,
|
||||||
|
@ -641,9 +641,6 @@ bool terminal_enter(void)
|
|||||||
curwin->w_p_so = 0;
|
curwin->w_p_so = 0;
|
||||||
curwin->w_p_siso = 0;
|
curwin->w_p_siso = 0;
|
||||||
|
|
||||||
// Save the existing cursor entry since it may be modified by the application
|
|
||||||
cursorentry_T save_cursorentry = shape_table[SHAPE_IDX_TERM];
|
|
||||||
|
|
||||||
// Update the cursor shape table and flush changes to the UI
|
// Update the cursor shape table and flush changes to the UI
|
||||||
s->term->pending.cursor = true;
|
s->term->pending.cursor = true;
|
||||||
refresh_cursor(s->term);
|
refresh_cursor(s->term);
|
||||||
@ -674,8 +671,8 @@ bool terminal_enter(void)
|
|||||||
RedrawingDisabled = s->save_rd;
|
RedrawingDisabled = s->save_rd;
|
||||||
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
|
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
|
||||||
|
|
||||||
shape_table[SHAPE_IDX_TERM] = save_cursorentry;
|
// Restore the terminal cursor to what is set in 'guicursor'
|
||||||
ui_mode_info_set();
|
(void)parse_shape_opt(SHAPE_CURSOR);
|
||||||
|
|
||||||
if (save_curwin == curwin->handle) { // Else: window was closed.
|
if (save_curwin == curwin->handle) { // Else: window was closed.
|
||||||
curwin->w_p_cul = save_w_p_cul;
|
curwin->w_p_cul = save_w_p_cul;
|
||||||
|
@ -15,9 +15,20 @@ local skip = t.skip
|
|||||||
describe(':terminal cursor', function()
|
describe(':terminal cursor', function()
|
||||||
local screen
|
local screen
|
||||||
|
|
||||||
|
local terminal_mode_idx ---@type number
|
||||||
|
|
||||||
before_each(function()
|
before_each(function()
|
||||||
clear()
|
clear()
|
||||||
screen = tt.setup_screen()
|
screen = tt.setup_screen()
|
||||||
|
|
||||||
|
if terminal_mode_idx == nil then
|
||||||
|
for i, v in ipairs(screen._mode_info) do
|
||||||
|
if v.name == 'terminal' then
|
||||||
|
terminal_mode_idx = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(terminal_mode_idx)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('moves the screen cursor when focused', function()
|
it('moves the screen cursor when focused', function()
|
||||||
@ -143,13 +154,6 @@ describe(':terminal cursor', function()
|
|||||||
|
|
||||||
it('can be modified by application #3681', function()
|
it('can be modified by application #3681', function()
|
||||||
skip(is_os('win'), '#31587')
|
skip(is_os('win'), '#31587')
|
||||||
local idx ---@type number
|
|
||||||
for i, v in ipairs(screen._mode_info) do
|
|
||||||
if v.name == 'terminal' then
|
|
||||||
idx = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert(idx)
|
|
||||||
|
|
||||||
local states = {
|
local states = {
|
||||||
[1] = { blink = true, shape = 'block' },
|
[1] = { blink = true, shape = 'block' },
|
||||||
@ -171,13 +175,13 @@ describe(':terminal cursor', function()
|
|||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
if v.blink then
|
if v.blink then
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
else
|
else
|
||||||
eq(0, screen._mode_info[idx].blinkon)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(0, screen._mode_info[idx].blinkoff)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
end
|
end
|
||||||
eq(v.shape, screen._mode_info[idx].cursor_shape)
|
eq(v.shape, screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
@ -191,20 +195,13 @@ describe(':terminal cursor', function()
|
|||||||
]])
|
]])
|
||||||
|
|
||||||
-- Cursor returns to default on TermLeave
|
-- Cursor returns to default on TermLeave
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('block', screen._mode_info[idx].cursor_shape)
|
eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can be modified per terminal', function()
|
it('can be modified per terminal', function()
|
||||||
skip(is_os('win'), '#31587')
|
skip(is_os('win'), '#31587')
|
||||||
local idx ---@type number
|
|
||||||
for i, v in ipairs(screen._mode_info) do
|
|
||||||
if v.name == 'terminal' then
|
|
||||||
idx = i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
assert(idx)
|
|
||||||
|
|
||||||
-- Set cursor to vertical bar with blink
|
-- Set cursor to vertical bar with blink
|
||||||
tt.feed_csi('5 q')
|
tt.feed_csi('5 q')
|
||||||
@ -216,9 +213,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('vertical', screen._mode_info[idx].cursor_shape)
|
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -231,9 +228,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('vertical', screen._mode_info[idx].cursor_shape)
|
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -256,9 +253,9 @@ describe(':terminal cursor', function()
|
|||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
-- New terminal, cursor resets to defaults
|
-- New terminal, cursor resets to defaults
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('block', screen._mode_info[idx].cursor_shape)
|
eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -275,9 +272,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(0, screen._mode_info[idx].blinkon)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(0, screen._mode_info[idx].blinkoff)
|
eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('horizontal', screen._mode_info[idx].cursor_shape)
|
eq('horizontal', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -294,9 +291,9 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]],
|
]],
|
||||||
condition = function()
|
condition = function()
|
||||||
eq(500, screen._mode_info[idx].blinkon)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
|
||||||
eq(500, screen._mode_info[idx].blinkoff)
|
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
|
||||||
eq('vertical', screen._mode_info[idx].cursor_shape)
|
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
@ -326,6 +323,32 @@ describe(':terminal cursor', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('preserves guicursor value on TermLeave #31612', function()
|
||||||
|
eq(3, screen._mode_info[terminal_mode_idx].hl_id)
|
||||||
|
|
||||||
|
-- Change 'guicursor' while terminal mode is active
|
||||||
|
command('set guicursor+=t:Error')
|
||||||
|
|
||||||
|
local error_hl_id = call('hlID', 'Error')
|
||||||
|
|
||||||
|
screen:expect({
|
||||||
|
condition = function()
|
||||||
|
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Exit terminal mode
|
||||||
|
feed([[<C-\><C-N>]])
|
||||||
|
|
||||||
|
screen:expect([[
|
||||||
|
tty ready |
|
||||||
|
^ |
|
||||||
|
|*5
|
||||||
|
]])
|
||||||
|
|
||||||
|
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('buffer cursor position is correct in terminal without number column', function()
|
describe('buffer cursor position is correct in terminal without number column', function()
|
||||||
@ -350,12 +373,6 @@ describe('buffer cursor position is correct in terminal without number column',
|
|||||||
}, {
|
}, {
|
||||||
cols = 70,
|
cols = 70,
|
||||||
})
|
})
|
||||||
screen:set_default_attr_ids({
|
|
||||||
[1] = { foreground = 253, background = 11 },
|
|
||||||
[2] = { reverse = true },
|
|
||||||
[3] = { bold = true },
|
|
||||||
[4] = { background = 11 },
|
|
||||||
})
|
|
||||||
-- Also check for real cursor position, as it is used for stuff like input methods
|
-- Also check for real cursor position, as it is used for stuff like input methods
|
||||||
screen._handle_busy_start = function() end
|
screen._handle_busy_start = function() end
|
||||||
screen._handle_busy_stop = function() end
|
screen._handle_busy_stop = function() end
|
||||||
@ -667,13 +684,6 @@ describe('buffer cursor position is correct in terminal with number column', fun
|
|||||||
}, {
|
}, {
|
||||||
cols = 70,
|
cols = 70,
|
||||||
})
|
})
|
||||||
screen:set_default_attr_ids({
|
|
||||||
[1] = { foreground = 253, background = 11 },
|
|
||||||
[2] = { reverse = true },
|
|
||||||
[3] = { bold = true },
|
|
||||||
[4] = { background = 11 },
|
|
||||||
[7] = { foreground = 130 },
|
|
||||||
})
|
|
||||||
-- Also check for real cursor position, as it is used for stuff like input methods
|
-- Also check for real cursor position, as it is used for stuff like input methods
|
||||||
screen._handle_busy_start = function() end
|
screen._handle_busy_start = function() end
|
||||||
screen._handle_busy_stop = function() end
|
screen._handle_busy_stop = function() end
|
||||||
|
@ -5294,9 +5294,9 @@ describe('builtin popupmenu', function()
|
|||||||
feed('S hello helio hero h<C-X><C-P>')
|
feed('S hello helio hero h<C-X><C-P>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
hello helio hero h^ |
|
hello helio hero h^ |
|
||||||
{1:~ }{n: }{mn:h}{n:ello }{1: }|
|
{1:~ }{n: }{mn:h}{n:ero }{1: }|
|
||||||
{1:~ }{n: }{mn:h}{n:elio }{1: }|
|
{1:~ }{n: }{mn:h}{n:elio }{1: }|
|
||||||
{1:~ }{s: }{ms:h}{s:ero }{1: }|
|
{1:~ }{s: }{ms:h}{s:ello }{1: }|
|
||||||
{1:~ }|*15
|
{1:~ }|*15
|
||||||
{2:-- }{5:match 1 of 3} |
|
{2:-- }{5:match 1 of 3} |
|
||||||
]])
|
]])
|
||||||
@ -5304,13 +5304,20 @@ describe('builtin popupmenu', function()
|
|||||||
feed('<Esc>S hello helio hero h<C-X><C-P><C-P>')
|
feed('<Esc>S hello helio hero h<C-X><C-P><C-P>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
hello helio hero h^ |
|
hello helio hero h^ |
|
||||||
{1:~ }{n: }{mn:h}{n:ello }{1: }|
|
|
||||||
{1:~ }{s: }{ms:h}{s:elio }{1: }|
|
|
||||||
{1:~ }{n: }{mn:h}{n:ero }{1: }|
|
{1:~ }{n: }{mn:h}{n:ero }{1: }|
|
||||||
|
{1:~ }{s: }{ms:h}{s:elio }{1: }|
|
||||||
|
{1:~ }{n: }{mn:h}{n:ello }{1: }|
|
||||||
{1:~ }|*15
|
{1:~ }|*15
|
||||||
{2:-- }{5:match 2 of 3} |
|
{2:-- }{5:match 2 of 3} |
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
feed('<Esc>S/non_existing_folder<C-X><C-F>')
|
||||||
|
screen:expect([[
|
||||||
|
/non_existing_folder^ |
|
||||||
|
{1:~ }|*18
|
||||||
|
{2:-- }{6:Pattern not found} |
|
||||||
|
]])
|
||||||
|
|
||||||
feed('<C-E><Esc>')
|
feed('<C-E><Esc>')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -2830,16 +2830,113 @@ func Test_complete_fuzzy_match()
|
|||||||
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
call assert_equal('hello help hero h', getline('.'))
|
call assert_equal('hello help hero h', getline('.'))
|
||||||
|
|
||||||
|
set completeopt-=noinsert
|
||||||
|
call setline(1, ['xyz yxz x'])
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('xyz yxz xyz', getline('.'))
|
||||||
|
" can fuzzy get yxz when use Ctrl-N twice
|
||||||
|
call setline(1, ['xyz yxz x'])
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('xyz yxz yxz', getline('.'))
|
||||||
|
|
||||||
|
call setline(1, ['你好 你'])
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('你好 你好', getline('.'))
|
||||||
|
call setline(1, ['你的 我的 的'])
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('你的 我的 你的', getline('.'))
|
||||||
|
" can fuzzy get multiple-byte word when use Ctrl-N twice
|
||||||
|
call setline(1, ['你的 我的 的'])
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('你的 我的 我的', getline('.'))
|
||||||
|
|
||||||
|
" respect wrapscan
|
||||||
|
set nowrapscan
|
||||||
|
call setline(1, ["xyz", "yxz", ""])
|
||||||
|
call cursor(3, 1)
|
||||||
|
call feedkeys("Sy\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('y', getline('.'))
|
||||||
|
set wrapscan
|
||||||
|
call feedkeys("Sy\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('xyz', getline('.'))
|
||||||
|
|
||||||
|
" fuzzy on file
|
||||||
|
call writefile([''], 'fobar', 'D')
|
||||||
|
call writefile([''], 'foobar', 'D')
|
||||||
|
call setline(1, ['fob'])
|
||||||
|
call cursor(1, 1)
|
||||||
|
call feedkeys("A\<C-X>\<C-f>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('fobar', getline('.'))
|
||||||
|
call feedkeys("Sfob\<C-X>\<C-f>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('foobar', getline('.'))
|
||||||
|
call feedkeys("S../\<C-X>\<C-f>\<Esc>0", 'tx!')
|
||||||
|
call assert_match('../*', getline('.'))
|
||||||
|
call feedkeys("S../td\<C-X>\<C-f>\<Esc>0", 'tx!')
|
||||||
|
call assert_match('../testdir', getline('.'))
|
||||||
|
|
||||||
|
" can get completion from other buffer
|
||||||
|
set completeopt=fuzzy,menu,menuone
|
||||||
|
vnew
|
||||||
|
call setline(1, ["completeness,", "compatibility", "Composite", "Omnipotent"])
|
||||||
|
wincmd p
|
||||||
|
call feedkeys("Somp\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('completeness', getline('.'))
|
||||||
|
call feedkeys("Somp\<C-N>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('compatibility', getline('.'))
|
||||||
|
call feedkeys("Somp\<C-P>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('Omnipotent', getline('.'))
|
||||||
|
call feedkeys("Somp\<C-P>\<C-P>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('Composite', getline('.'))
|
||||||
|
call feedkeys("S omp\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal(' completeness', getline('.'))
|
||||||
|
|
||||||
|
" fuzzy on whole line completion
|
||||||
|
call setline(1, ["world is on fire", "no one can save me but you", 'user can execute', ''])
|
||||||
|
call cursor(4, 1)
|
||||||
|
call feedkeys("Swio\<C-X>\<C-L>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('world is on fire', getline('.'))
|
||||||
|
call feedkeys("Su\<C-X>\<C-L>\<C-P>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('no one can save me but you', getline('.'))
|
||||||
|
|
||||||
|
" issue #15412
|
||||||
|
call setline(1, ['alpha bravio charlie'])
|
||||||
|
call feedkeys("Salpha\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha bravio', getline('.'))
|
||||||
|
call feedkeys("Salp\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha', getline('.'))
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha bravio', getline('.'))
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha bravio charlie', getline('.'))
|
||||||
|
|
||||||
|
set complete-=i
|
||||||
|
call feedkeys("Salp\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha', getline('.'))
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha bravio', getline('.'))
|
||||||
|
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha bravio charlie', getline('.'))
|
||||||
|
|
||||||
|
call setline(1, ['alpha bravio charlie', 'alpha another'])
|
||||||
|
call feedkeys("Salpha\<C-X>\<C-N>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('alpha another', getline('.'))
|
||||||
|
call setline(1, ['你好 我好', '你好 他好'])
|
||||||
|
call feedkeys("S你好\<C-X>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('你好 我好', getline('.'))
|
||||||
|
call feedkeys("S你好\<C-X>\<C-N>\<C-N>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('你好 他好', getline('.'))
|
||||||
|
|
||||||
" issue #15526
|
" issue #15526
|
||||||
set completeopt=fuzzy,menuone,menu,noselect
|
set completeopt=fuzzy,menuone,menu,noselect
|
||||||
call setline(1, ['Text', 'ToText', ''])
|
call setline(1, ['Text', 'ToText', ''])
|
||||||
call cursor(2, 1)
|
call cursor(3, 1)
|
||||||
call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!')
|
call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!')
|
||||||
call assert_equal('Tex', getline('.'))
|
call assert_equal('Tex', getline('.'))
|
||||||
|
|
||||||
" clean up
|
" clean up
|
||||||
set omnifunc=
|
set omnifunc=
|
||||||
bw!
|
bw!
|
||||||
|
bw!
|
||||||
set complete& completeopt&
|
set complete& completeopt&
|
||||||
autocmd! AAAAA_Group
|
autocmd! AAAAA_Group
|
||||||
augroup! AAAAA_Group
|
augroup! AAAAA_Group
|
||||||
@ -2850,6 +2947,38 @@ func Test_complete_fuzzy_match()
|
|||||||
unlet g:word
|
unlet g:word
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_complete_fuzzy_with_completeslash()
|
||||||
|
CheckMSWindows
|
||||||
|
|
||||||
|
call writefile([''], 'fobar', 'D')
|
||||||
|
let orig_shellslash = &shellslash
|
||||||
|
set cpt&
|
||||||
|
new
|
||||||
|
set completeopt+=fuzzy
|
||||||
|
set noshellslash
|
||||||
|
|
||||||
|
" Test with completeslash unset
|
||||||
|
set completeslash=
|
||||||
|
call setline(1, ['.\fob'])
|
||||||
|
call feedkeys("A\<C-X>\<C-F>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('.\fobar', getline('.'))
|
||||||
|
|
||||||
|
" Test with completeslash=backslash
|
||||||
|
set completeslash=backslash
|
||||||
|
call feedkeys("S.\\fob\<C-X>\<C-F>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('.\fobar', getline('.'))
|
||||||
|
|
||||||
|
" Test with completeslash=slash
|
||||||
|
set completeslash=slash
|
||||||
|
call feedkeys("S.\\fob\<C-X>\<C-F>\<Esc>0", 'tx!')
|
||||||
|
call assert_equal('./fobar', getline('.'))
|
||||||
|
|
||||||
|
" Reset and clean up
|
||||||
|
let &shellslash = orig_shellslash
|
||||||
|
set completeslash=
|
||||||
|
%bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Check that tie breaking is stable for completeopt+=fuzzy (which should
|
" Check that tie breaking is stable for completeopt+=fuzzy (which should
|
||||||
" behave the same on different platforms).
|
" behave the same on different platforms).
|
||||||
func Test_complete_fuzzy_match_tie()
|
func Test_complete_fuzzy_match_tie()
|
||||||
@ -2870,4 +2999,14 @@ func Test_complete_fuzzy_match_tie()
|
|||||||
set completeopt&
|
set completeopt&
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_complete_backwards_default()
|
||||||
|
new
|
||||||
|
call append(1, ['foobar', 'foobaz'])
|
||||||
|
new
|
||||||
|
call feedkeys("i\<c-p>", 'tx')
|
||||||
|
call assert_equal('foobaz', getline('.'))
|
||||||
|
bw!
|
||||||
|
bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
|
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
|
||||||
|
@ -1513,6 +1513,11 @@ func Test_pum_highlights_match()
|
|||||||
call TermWait(buf, 50)
|
call TermWait(buf, 50)
|
||||||
call VerifyScreenDump(buf, 'Test_pum_highlights_11', {})
|
call VerifyScreenDump(buf, 'Test_pum_highlights_11', {})
|
||||||
|
|
||||||
|
" issue #15357
|
||||||
|
call term_sendkeys(buf, "\<ESC>S/non_existing_folder\<C-X>\<C-F>")
|
||||||
|
call TermWait(buf, 50)
|
||||||
|
call VerifyScreenDump(buf, 'Test_pum_highlights_15', {})
|
||||||
|
|
||||||
call term_sendkeys(buf, "\<C-E>\<Esc>")
|
call term_sendkeys(buf, "\<C-E>\<Esc>")
|
||||||
call TermWait(buf)
|
call TermWait(buf)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user