aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/insexpand.c690
1 files changed, 350 insertions, 340 deletions
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 5655b31df1..4b0613229b 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -140,6 +140,21 @@ struct compl_S {
int cp_number; ///< sequence number
};
+/// state information used for getting the next set of insert completion
+/// matches.
+typedef struct {
+ char *e_cpt; ///< current entry in 'complete'
+ buf_T *ins_buf; ///< buffer being scanned
+ pos_T *cur_match_pos; ///< current match position
+ pos_T prev_match_pos; ///< previous match position
+ bool set_match_pos; ///< save first_match_pos/last_match_pos
+ pos_T first_match_pos; ///< first match position
+ pos_T last_match_pos; ///< last match position
+ bool found_all; ///< found all matches of a certain type.
+ char_u *dict; ///< dictionary file to search
+ int dict_f; ///< "dict" is an exact file name or not
+} ins_compl_next_state_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "insexpand.c.generated.h"
#endif
@@ -162,6 +177,7 @@ static char e_compldel[] = N_("E840: Completion function deleted text");
// "compl_curr_match" points to the currently selected entry.
// "compl_shown_match" is different from compl_curr_match during
// ins_compl_get_exp().
+// "compl_old_match" points to previous "compl_curr_match".
static compl_T *compl_first_match = NULL;
static compl_T *compl_curr_match = NULL;
@@ -445,6 +461,12 @@ bool vim_is_ctrl_x_key(int c)
return false;
}
+/// @return true if "match" is the original text when the completion began.
+static bool match_at_original_text(const compl_T *const match)
+{
+ return match->cp_flags & CP_ORIGINAL_TEXT;
+}
+
/// Check that character "c" is part of the item currently being
/// completed. Used to decide whether to abandon complete mode when the menu
/// is visible.
@@ -479,6 +501,88 @@ bool ins_compl_accept_char(int c)
return vim_iswordc(c);
}
+/// Get the completed text by inferring the case of the originally typed text.
+static char_u *ins_compl_infercase_gettext(char_u *str, int actual_len, int actual_compl_length,
+ int min_len)
+{
+ bool has_lower = false;
+ bool was_letter = false;
+
+ // Allocate wide character array for the completion and fill it.
+ int *const wca = xmalloc((size_t)actual_len * sizeof(*wca));
+ {
+ const char_u *p = str;
+ for (int i = 0; i < actual_len; i++) {
+ wca[i] = mb_ptr2char_adv(&p);
+ }
+ }
+
+ // Rule 1: Were any chars converted to lower?
+ {
+ const char_u *p = compl_orig_text;
+ for (int i = 0; i < min_len; i++) {
+ const int c = mb_ptr2char_adv(&p);
+ if (mb_islower(c)) {
+ has_lower = true;
+ if (mb_isupper(wca[i])) {
+ // Rule 1 is satisfied.
+ for (i = actual_compl_length; i < actual_len; i++) {
+ wca[i] = mb_tolower(wca[i]);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Rule 2: No lower case, 2nd consecutive letter converted to
+ // upper case.
+ if (!has_lower) {
+ const char_u *p = compl_orig_text;
+ for (int i = 0; i < min_len; i++) {
+ const int c = mb_ptr2char_adv(&p);
+ if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
+ // Rule 2 is satisfied.
+ for (i = actual_compl_length; i < actual_len; i++) {
+ wca[i] = mb_toupper(wca[i]);
+ }
+ break;
+ }
+ was_letter = mb_islower(c) || mb_isupper(c);
+ }
+ }
+
+ // Copy the original case of the part we typed.
+ {
+ const char_u *p = compl_orig_text;
+ for (int i = 0; i < min_len; i++) {
+ const int c = mb_ptr2char_adv(&p);
+ if (mb_islower(c)) {
+ wca[i] = mb_tolower(wca[i]);
+ } else if (mb_isupper(c)) {
+ wca[i] = mb_toupper(wca[i]);
+ }
+ }
+ }
+
+ // Generate encoding specific output from wide character array.
+ // Multi-byte characters can occupy up to five bytes more than
+ // ASCII characters, and we also need one byte for NUL, so stay
+ // six bytes away from the edge of IObuff.
+ {
+ char_u *p = IObuff;
+ int i = 0;
+ while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
+ p += utf_char2bytes(wca[i++], (char *)p);
+ }
+ *p = NUL;
+ }
+
+ xfree(wca);
+
+ return IObuff;
+}
+
/// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
/// case of the originally typed text is used, and the case of the completed
/// text is inferred, ie this tries to work out what case you probably wanted
@@ -490,12 +594,9 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
FUNC_ATTR_NONNULL_ARG(1)
{
char_u *str = str_arg;
- int i, c;
int actual_len; // Take multi-byte characters
int actual_compl_length; // into account.
int min_len;
- bool has_lower = false;
- bool was_letter = false;
int flags = 0;
if (p_ic && curbuf->b_p_inf && len > 0) {
@@ -526,79 +627,7 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
min_len = actual_len < actual_compl_length
? actual_len : actual_compl_length;
- // Allocate wide character array for the completion and fill it.
- int *const wca = xmalloc((size_t)actual_len * sizeof(*wca));
- {
- const char_u *p = str;
- for (i = 0; i < actual_len; i++) {
- wca[i] = mb_ptr2char_adv(&p);
- }
- }
-
- // Rule 1: Were any chars converted to lower?
- {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&p);
- if (mb_islower(c)) {
- has_lower = true;
- if (mb_isupper(wca[i])) {
- // Rule 1 is satisfied.
- for (i = actual_compl_length; i < actual_len; i++) {
- wca[i] = mb_tolower(wca[i]);
- }
- break;
- }
- }
- }
- }
-
- // Rule 2: No lower case, 2nd consecutive letter converted to
- // upper case.
- if (!has_lower) {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&p);
- if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
- // Rule 2 is satisfied.
- for (i = actual_compl_length; i < actual_len; i++) {
- wca[i] = mb_toupper(wca[i]);
- }
- break;
- }
- was_letter = mb_islower(c) || mb_isupper(c);
- }
- }
-
- // Copy the original case of the part we typed.
- {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&p);
- if (mb_islower(c)) {
- wca[i] = mb_tolower(wca[i]);
- } else if (mb_isupper(c)) {
- wca[i] = mb_toupper(wca[i]);
- }
- }
- }
-
- // Generate encoding specific output from wide character array.
- // Multi-byte characters can occupy up to five bytes more than
- // ASCII characters, and we also need one byte for NUL, so stay
- // six bytes away from the edge of IObuff.
- {
- char_u *p = IObuff;
- i = 0;
- while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
- p += utf_char2bytes(wca[i++], (char *)p);
- }
- *p = NUL;
- }
-
- xfree(wca);
-
- str = IObuff;
+ str = ins_compl_infercase_gettext(str, actual_len, actual_compl_length, min_len);
}
if (cont_s_ipos) {
flags |= CP_CONT_S_IPOS;
@@ -661,7 +690,7 @@ static int ins_compl_add(char_u *const str, int len, char_u *const fname,
if (compl_first_match != NULL && !adup) {
match = compl_first_match;
do {
- if (!(match->cp_flags & CP_ORIGINAL_TEXT)
+ if (!match_at_original_text(match)
&& STRNCMP(match->cp_str, str, len) == 0
&& match->cp_str[len] == NUL) {
FREE_CPTEXT(cptext, cptext_allocated);
@@ -777,6 +806,7 @@ static void ins_compl_longest_match(compl_T *match)
if (compl_leader == NULL) {
// First match, use it as a whole.
compl_leader = vim_strsave(match->cp_str);
+
had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete();
ins_bytes(compl_leader + get_compl_len());
@@ -788,40 +818,42 @@ static void ins_compl_longest_match(compl_T *match)
ins_compl_delete();
}
compl_used_match = false;
- } else {
- // Reduce the text if this match differs from compl_leader.
- p = compl_leader;
- s = match->cp_str;
- while (*p != NUL) {
- c1 = utf_ptr2char((char *)p);
- c2 = utf_ptr2char((char *)s);
-
- if ((match->cp_flags & CP_ICASE)
- ? (mb_tolower(c1) != mb_tolower(c2))
- : (c1 != c2)) {
- break;
- }
- MB_PTR_ADV(p);
- MB_PTR_ADV(s);
- }
- if (*p != NUL) {
- // Leader was shortened, need to change the inserted text.
- *p = NUL;
- had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + get_compl_len());
- ins_redraw(false);
+ return;
+ }
- // When the match isn't there (to avoid matching itself) remove it
- // again after redrawing.
- if (!had_match) {
- ins_compl_delete();
- }
+ // Reduce the text if this match differs from compl_leader.
+ p = compl_leader;
+ s = match->cp_str;
+ while (*p != NUL) {
+ c1 = utf_ptr2char((char *)p);
+ c2 = utf_ptr2char((char *)s);
+
+ if ((match->cp_flags & CP_ICASE)
+ ? (mb_tolower(c1) != mb_tolower(c2))
+ : (c1 != c2)) {
+ break;
}
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(s);
+ }
- compl_used_match = false;
+ if (*p != NUL) {
+ // Leader was shortened, need to change the inserted text.
+ *p = NUL;
+ had_match = (curwin->w_cursor.col > compl_col);
+ ins_compl_delete();
+ ins_bytes(compl_leader + get_compl_len());
+ ins_redraw(false);
+
+ // When the match isn't there (to avoid matching itself) remove it
+ // again after redrawing.
+ if (!had_match) {
+ ins_compl_delete();
+ }
}
+
+ compl_used_match = false;
}
/// Add an array of matches to the list of matches.
@@ -846,20 +878,21 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase)
/// Return the number of matches (excluding the original).
static int ins_compl_make_cyclic(void)
{
- compl_T *match;
- int count = 0;
+ if (compl_first_match == NULL) {
+ return 0;
+ }
- if (compl_first_match != NULL) {
- // Find the end of the list.
- match = compl_first_match;
- // there's always an entry for the compl_orig_text, it doesn't count.
- while (match->cp_next != NULL && match->cp_next != compl_first_match) {
- match = match->cp_next;
- count++;
- }
- match->cp_next = compl_first_match;
- compl_first_match->cp_prev = match;
+ // Find the end of the list.
+ compl_T *match = compl_first_match;
+ int count = 0;
+ // there's always an entry for the compl_orig_text, it doesn't count.
+ while (match->cp_next != NULL && match->cp_next != compl_first_match) {
+ match = match->cp_next;
+ count++;
}
+ match->cp_next = compl_first_match;
+ compl_first_match->cp_prev = match;
+
return count;
}
@@ -898,10 +931,12 @@ static int compl_match_arraysize;
/// Remove any popup menu.
static void ins_compl_del_pum(void)
{
- if (compl_match_array != NULL) {
- pum_undisplay(false);
- XFREE_CLEAR(compl_match_array);
+ if (compl_match_array == NULL) {
+ return;
}
+
+ pum_undisplay(false);
+ XFREE_CLEAR(compl_match_array);
}
/// Check if the popup menu should be displayed.
@@ -919,15 +954,14 @@ static bool pum_enough_matches(void)
{
// Don't display the popup menu if there are no matches or there is only
// one (ignoring the original text).
- compl_T *comp = compl_first_match;
+ compl_T *compl = compl_first_match;
int i = 0;
do {
- if (comp == NULL
- || ((comp->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2)) {
+ if (compl == NULL || (!match_at_original_text(compl) && ++i == 2)) {
break;
}
- comp = comp->cp_next;
- } while (comp != compl_first_match);
+ compl = compl->cp_next;
+ } while (compl != compl_first_match);
if (strstr((char *)p_cot, "menuone") != NULL) {
return i >= 1;
@@ -1019,7 +1053,7 @@ void ins_compl_show_pum(void)
lead_len = (int)STRLEN(compl_leader);
}
do {
- if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
+ if (!match_at_original_text(compl)
&& (compl_leader == NULL
|| ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
compl_match_arraysize++;
@@ -1034,14 +1068,14 @@ void ins_compl_show_pum(void)
compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
// If the current match is the original text don't find the first
// match after it, don't highlight anything.
- if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
+ if (match_at_original_text(compl_shown_match)) {
shown_match_ok = true;
}
i = 0;
compl = compl_first_match;
do {
- if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
+ if (!match_at_original_text(compl)
&& (compl_leader == NULL
|| ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
if (!shown_match_ok) {
@@ -1080,7 +1114,7 @@ void ins_compl_show_pum(void)
// When the original text is the shown match don't set
// compl_shown_match.
- if (compl->cp_flags & CP_ORIGINAL_TEXT) {
+ if (match_at_original_text(compl)) {
shown_match_ok = true;
}
@@ -1255,8 +1289,7 @@ static void ins_compl_files(int count, char **files, int thesaurus, int flags, r
// Read dictionary file line by line.
// Check each line for a match.
- while (!got_int && !compl_interrupted
- && !vim_fgets(buf, LSIZE, fp)) {
+ while (!got_int && !compl_interrupted && !vim_fgets(buf, LSIZE, fp)) {
ptr = buf;
while (vim_regexec(regmatch, (char *)buf, (colnr_T)(ptr - buf))) {
ptr = regmatch->startp[0];
@@ -1603,13 +1636,13 @@ static void ins_compl_set_original_text(char_u *str)
FUNC_ATTR_NONNULL_ALL
{
// Replace the original text entry.
- // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly be
- // at the last item for backward completion
- if (compl_first_match->cp_flags & CP_ORIGINAL_TEXT) { // safety check
+ // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly
+ // be at the last item for backward completion
+ if (match_at_original_text(compl_first_match)) { // safety check
xfree(compl_first_match->cp_str);
compl_first_match->cp_str = vim_strsave(str);
} else if (compl_first_match->cp_prev != NULL
- && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT)) {
+ && match_at_original_text(compl_first_match->cp_prev)) {
xfree(compl_first_match->cp_prev->cp_str);
compl_first_match->cp_prev->cp_str = vim_strsave(str);
}
@@ -1628,20 +1661,20 @@ void ins_compl_addfrommatch(void)
if ((int)STRLEN(p) <= len) { // the match is too short
// When still at the original match use the first entry that matches
// the leader.
- if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
- p = NULL;
- for (cp = compl_shown_match->cp_next; cp != NULL
- && cp != compl_first_match; cp = cp->cp_next) {
- if (compl_leader == NULL
- || ins_compl_equal(cp, compl_leader, STRLEN(compl_leader))) {
- p = cp->cp_str;
- break;
- }
- }
- if (p == NULL || (int)STRLEN(p) <= len) {
- return;
+ if (!match_at_original_text(compl_shown_match)) {
+ return;
+ }
+
+ p = NULL;
+ for (cp = compl_shown_match->cp_next; cp != NULL
+ && cp != compl_first_match; cp = cp->cp_next) {
+ if (compl_leader == NULL
+ || ins_compl_equal(cp, compl_leader, STRLEN(compl_leader))) {
+ p = cp->cp_str;
+ break;
}
- } else {
+ }
+ if (p == NULL || (int)STRLEN(p) <= len) {
return;
}
}
@@ -2451,7 +2484,7 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
if (ret == OK && compl_first_match != NULL) {
compl_T *match = compl_first_match;
do {
- if (!(match->cp_flags & CP_ORIGINAL_TEXT)) {
+ if (!match_at_original_text(match)) {
dict_T *di = tv_dict_alloc();
tv_list_append_dict(li, di);
@@ -2516,105 +2549,101 @@ enum {
INS_COMPL_CPT_END,
};
-/// Process the next 'complete' option value in "e_cpt_arg".
+/// Process the next 'complete' option value in st->e_cpt.
///
/// If successful, the arguments are set as below:
-/// e_cpt_arg - pointer to the next option value in 'e_cpt_arg'
+/// st->cpt - pointer to the next option value in "st->cpt"
/// 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
+/// st->found_all - all matches of this type are found
+/// st->ins_buf - search for completions in this buffer
+/// st->first_match_pos - position of the first completion match
+/// st->last_match_pos - position of the last completion match
+/// st->set_match_pos - true if the first match position should be saved to
+/// avoid loops after the search wraps around.
+/// st->dict - name of the dictionary or thesaurus file to search
+/// 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.
/// 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)
+/// 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,
+ pos_T *start_match_pos)
{
- 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++;
+ st->found_all = false;
+
+ while (*st->e_cpt == ',' || *st->e_cpt == ' ') {
+ st->e_cpt++;
}
- if (*e_cpt == '.' && !curbuf->b_scanned) {
- buf = curbuf;
- *first_match_pos = *start_match_pos;
+
+ if (*st->e_cpt == '.' && !curbuf->b_scanned) {
+ st->ins_buf = curbuf;
+ st->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) {
+ if (ctrl_x_mode_normal() && dec(&st->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));
+ st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count;
+ st->first_match_pos.col = (colnr_T)STRLEN(ml_get(st->first_match_pos.lnum));
}
- *last_match_pos = *first_match_pos;
+ st->last_match_pos = st->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) {
+ st->set_match_pos = true;
+ } else if (vim_strchr("buwU", *st->e_cpt) != NULL
+ && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != curbuf) {
// Scan a buffer, but not the current one.
- if (buf->b_ml.ml_mfp != NULL) { // loaded buffer
+ if (st->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 = buf->b_ml.ml_line_count + 1;
- last_match_pos->lnum = 0;
+ st->first_match_pos.col = st->last_match_pos.col = 0;
+ st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count + 1;
+ st->last_match_pos.lnum = 0;
compl_type = 0;
} else { // unloaded buffer, scan like dictionary
- found_all = true;
- if (buf->b_fname == NULL) {
+ st->found_all = true;
+ if (st->ins_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;
+ st->dict = (char_u *)st->ins_buf->b_fname;
+ st->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);
+ st->ins_buf->b_fname == NULL
+ ? buf_spname(st->ins_buf)
+ : st->ins_buf->b_sfname == NULL
+ ? st->ins_buf->b_fname
+ : st->ins_buf->b_sfname);
(void)msg_trunc_attr((char *)IObuff, true, HL_ATTR(HLF_R));
- } else if (*e_cpt == NUL) {
+ } else if (*st->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') {
+ } else if (*st->e_cpt == 'k' || *st->e_cpt == 's') {
+ if (*st->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;
+ if (*++st->e_cpt != ',' && *st->e_cpt != NUL) {
+ st->dict = (char_u *)st->e_cpt;
+ st->dict_f = DICT_FIRST;
}
- } else if (*e_cpt == 'i') {
+ } else if (*st->e_cpt == 'i') {
compl_type = CTRL_X_PATH_PATTERNS;
- } else if (*e_cpt == 'd') {
+ } else if (*st->e_cpt == 'd') {
compl_type = CTRL_X_PATH_DEFINES;
- } else if (*e_cpt == ']' || *e_cpt == 't') {
+ } else if (*st->e_cpt == ']' || *st->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."));
@@ -2624,21 +2653,16 @@ static int process_next_cpt_value(char **e_cpt_arg, int *compl_type_arg, bool *f
}
// in any case e_cpt is advanced to the next entry
- (void)copy_option_part(&e_cpt, (char *)IObuff, IOSIZE, ",");
+ (void)copy_option_part(&st->e_cpt, (char *)IObuff, IOSIZE, ",");
- found_all = true;
+ st->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;
}
@@ -2656,20 +2680,19 @@ static void get_next_include_file_completion(int compl_type)
/// 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)
+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
+ 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,
+ dict != NULL ? dict_f : 0,
compl_type == CTRL_X_THESAURUS);
}
- *dict = NULL;
}
/// Get the next set of tag names matching "compl_pattern".
@@ -2833,29 +2856,18 @@ static char_u *ins_comp_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_p
/// 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
+/// Search for "compl_pattern" in the buffer "st->ins_buf" starting from the
+/// position "st->start_pos" in the "compl_direction" direction. If
+/// "st->set_match_pos" is true, then set the "st->first_match_pos" and
+/// "st->last_match_pos".
///
/// @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)
+static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
{
// 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) {
+ assert(st->ins_buf);
+ if (st->ins_buf->b_p_inf) {
p_scs = false;
}
@@ -2864,9 +2876,9 @@ static int get_next_default_completion(buf_T *ins_buf, pos_T *start_pos, pos_T *
// 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) {
+ if (st->ins_buf != curbuf) {
p_ws = false;
- } else if (scan_curbuf) {
+ } else if (*st->e_cpt == '.') {
p_ws = true;
}
bool looped_around = false;
@@ -2879,62 +2891,61 @@ static int get_next_default_completion(buf_T *ins_buf, pos_T *start_pos, pos_T *
// 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,
+ found_new_match = search_for_exact_line(st->ins_buf, st->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);
+ found_new_match = searchit(NULL, st->ins_buf, st->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) {
+ if (!compl_started || st->set_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) {
+ st->first_match_pos = *st->cur_match_pos;
+ st->last_match_pos = *st->cur_match_pos;
+ st->set_match_pos = false;
+ } else if (st->first_match_pos.lnum == st->last_match_pos.lnum
+ && st->first_match_pos.col == st->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))) {
+ && (st->prev_match_pos.lnum > st->cur_match_pos->lnum
+ || (st->prev_match_pos.lnum == st->cur_match_pos->lnum
+ && st->prev_match_pos.col >= st->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))) {
+ && (st->prev_match_pos.lnum < st->cur_match_pos->lnum
+ || (st->prev_match_pos.lnum == st->cur_match_pos->lnum
+ && st->prev_match_pos.col <= st->cur_match_pos->col))) {
if (looped_around) {
found_new_match = FAIL;
} else {
looped_around = true;
}
}
- *prev_match_pos = *cur_match_pos;
+ st->prev_match_pos = *st->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) {
+ if ((compl_cont_status & CONT_ADDING) && st->ins_buf == curbuf
+ && start_pos->lnum == st->cur_match_pos->lnum
+ && start_pos->col == st->cur_match_pos->col) {
continue;
}
int len;
- char_u *ptr = ins_comp_get_next_word_or_line(ins_buf, cur_match_pos, &len,
- &cont_s_ipos);
+ char_u *ptr = ins_comp_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
+ &len, &cont_s_ipos);
if (ptr == NULL) {
continue;
}
if (ins_compl_add_infercase(ptr, len, p_ic,
- ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
+ st->ins_buf == curbuf ? NULL : (char_u *)st->ins_buf->b_sfname,
0, cont_s_ipos) != NOTDONE) {
found_new_match = OK;
break;
@@ -2946,6 +2957,64 @@ static int get_next_default_completion(buf_T *ins_buf, pos_T *start_pos, pos_T *
return found_new_match;
}
+/// get the next set of completion matches for 'type'.
+/// @return true if a new match is found, otherwise false.
+static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini)
+{
+ int found_new_match = FAIL;
+
+ switch (type) {
+ case -1:
+ break;
+ case CTRL_X_PATH_PATTERNS:
+ case CTRL_X_PATH_DEFINES:
+ get_next_include_file_completion(type);
+ break;
+
+ case CTRL_X_DICTIONARY:
+ case CTRL_X_THESAURUS:
+ get_next_dict_tsr_completion(type, st->dict, st->dict_f);
+ st->dict = NULL;
+ break;
+
+ case CTRL_X_TAGS:
+ get_next_tag_completion();
+ break;
+
+ case CTRL_X_FILES:
+ get_next_filename_completion();
+ break;
+
+ case CTRL_X_CMDLINE:
+ case CTRL_X_CMDLINE_CTRL_X:
+ get_next_cmdline_completion();
+ break;
+
+ case CTRL_X_FUNCTION:
+ case CTRL_X_OMNI:
+ expand_by_function(type, (char_u *)compl_pattern);
+ break;
+
+ case CTRL_X_SPELL:
+ get_next_spell_completion(st->first_match_pos.lnum);
+ break;
+
+ default: // normal ^P/^N and ^X^L
+ found_new_match = get_next_default_completion(st, ini);
+ if (found_new_match == FAIL && st->ins_buf == curbuf) {
+ st->found_all = true;
+ }
+ }
+
+ // check if compl_curr_match has changed, (e.g. other type of
+ // expansion added something)
+ if (type != 0 && compl_curr_match != compl_old_match) {
+ found_new_match = OK;
+ }
+
+ return found_new_match;
+}
+
/// Get the next expansion(s), using "compl_pattern".
/// The search starts at position "ini" in curbuf and in the direction
/// compl_direction.
@@ -2955,21 +3024,10 @@ static int get_next_default_completion(buf_T *ins_buf, pos_T *start_pos, pos_T *
/// Return the total number of matches or -1 if still unknown -- Acevedo
static int ins_compl_get_exp(pos_T *ini)
{
- static pos_T first_match_pos;
- static pos_T last_match_pos;
- static char *e_cpt = ""; // curr. entry in 'complete'
- static bool found_all = false; // Found all matches of a
- // certain type.
- static buf_T *ins_buf = NULL; // buffer being scanned
-
- pos_T *pos;
+ static ins_compl_next_state_T st;
int i;
int found_new_match;
int type = ctrl_x_mode;
- char_u *dict = NULL;
- int dict_f = 0;
- bool set_match_pos;
- pos_T prev_pos = { 0, 0, 0 };
assert(curbuf != NULL);
@@ -2977,31 +3035,30 @@ static int ins_compl_get_exp(pos_T *ini)
FOR_ALL_BUFFERS(buf) {
buf->b_scanned = false;
}
- found_all = false;
- ins_buf = curbuf;
- e_cpt = (compl_cont_status & CONT_LOCAL) ? "." : (char *)curbuf->b_p_cpt;
- last_match_pos = first_match_pos = *ini;
- } else if (ins_buf != curbuf && !buf_valid(ins_buf)) {
- ins_buf = curbuf; // In case the buffer was wiped out.
+ st.found_all = false;
+ st.ins_buf = curbuf;
+ st.e_cpt = (compl_cont_status & CONT_LOCAL) ? "." : (char *)curbuf->b_p_cpt;
+ st.last_match_pos = st.first_match_pos = *ini;
+ } else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) {
+ st.ins_buf = curbuf; // In case the buffer was wiped out.
}
- assert(ins_buf != NULL);
+ assert(st.ins_buf != NULL);
compl_old_match = compl_curr_match; // remember the last current match
- pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
+ st.cur_match_pos = (compl_direction == FORWARD
+ ? &st.last_match_pos : &st.first_match_pos);
// For ^N/^P loop over all the flags/windows/buffers in 'complete'
for (;;) {
found_new_match = FAIL;
- set_match_pos = false;
+ st.set_match_pos = false;
// For ^N/^P pick a new entry from e_cpt if compl_started is off,
// or if found_all says this entry is done. For ^X^L only use the
// entries from 'complete' that look in loaded buffers.
if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
- && (!compl_started || found_all)) {
- int status = process_next_cpt_value(&e_cpt, &type, &found_all,
- &ins_buf, ini, &first_match_pos, &last_match_pos,
- &set_match_pos, &dict, &dict_f);
+ && (!compl_started || st.found_all)) {
+ int status = process_next_cpt_value(&st, &type, ini);
if (status == INS_COMPL_CPT_END) {
break;
}
@@ -3016,55 +3073,8 @@ static int ins_compl_get_exp(pos_T *ini)
break;
}
- switch (type) {
- case -1:
- break;
- case CTRL_X_PATH_PATTERNS:
- case CTRL_X_PATH_DEFINES:
- get_next_include_file_completion(type);
- break;
-
- case CTRL_X_DICTIONARY:
- case CTRL_X_THESAURUS:
- get_next_dict_tsr_completion(type, &dict, dict_f);
- break;
-
- case CTRL_X_TAGS:
- get_next_tag_completion();
- break;
-
- case CTRL_X_FILES:
- get_next_filename_completion();
- break;
-
- case CTRL_X_CMDLINE:
- case CTRL_X_CMDLINE_CTRL_X:
- get_next_cmdline_completion();
- break;
-
- case CTRL_X_FUNCTION:
- case CTRL_X_OMNI:
- expand_by_function(type, (char_u *)compl_pattern);
- break;
-
- case CTRL_X_SPELL:
- get_next_spell_completion(first_match_pos.lnum);
- break;
-
- default: // normal ^P/^N and ^X^L
- found_new_match = get_next_default_completion(ins_buf, ini, pos, &prev_pos,
- &set_match_pos, &first_match_pos,
- &last_match_pos, (*e_cpt == '.'));
- if (found_new_match == FAIL && ins_buf == curbuf) {
- found_all = true;
- }
- }
-
- // check if compl_curr_match has changed, (e.g. other type of
- // expansion added something)
- if (type != 0 && compl_curr_match != compl_old_match) {
- found_new_match = OK;
- }
+ // get the next set of completion matches
+ found_new_match = get_next_completion_match(type, &st, ini);
// break the loop for specialized modes (use 'complete' just for the
// generic ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new match
@@ -3088,8 +3098,8 @@ static int ins_compl_get_exp(pos_T *ini)
} else {
// Mark a buffer scanned when it has been scanned completely
if (type == 0 || type == CTRL_X_PATH_PATTERNS) {
- assert(ins_buf);
- ins_buf->b_scanned = true;
+ assert(st.ins_buf);
+ st.ins_buf->b_scanned = true;
}
compl_started = false;
@@ -3099,7 +3109,7 @@ static int ins_compl_get_exp(pos_T *ini)
if ((ctrl_x_mode_normal()
|| ctrl_x_mode_line_or_eval())
- && *e_cpt == NUL) { // Got to end of 'complete'
+ && *st.e_cpt == NUL) { // Got to end of 'complete'
found_new_match = FAIL;
}
@@ -3178,7 +3188,7 @@ void ins_compl_delete(void)
void ins_compl_insert(bool in_compl_func)
{
ins_bytes(compl_shown_match->cp_str + get_compl_len());
- compl_used_match = !(compl_shown_match->cp_flags & CP_ORIGINAL_TEXT);
+ compl_used_match = !match_at_original_text(compl_shown_match);
dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
@@ -3285,7 +3295,7 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
}
found_end = false;
}
- if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0
+ if (!match_at_original_text(compl_shown_match)
&& compl_leader != NULL
&& !ins_compl_equal(compl_shown_match,
compl_leader, STRLEN(compl_leader))) {
@@ -3340,7 +3350,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
}
if (compl_leader != NULL
- && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0) {
+ && !match_at_original_text(compl_shown_match)) {
// Update "compl_shown_match" to the actually shown match
ins_compl_update_shown_match();
}
@@ -3993,7 +4003,7 @@ static void ins_compl_show_statusmsg(void)
}
if (edit_submode_extra == NULL) {
- if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT) {
+ if (match_at_original_text(compl_curr_match)) {
edit_submode_extra = (char_u *)_("Back at original");
edit_submode_highl = HLF_W;
} else if (compl_cont_status & CONT_S_IPOS) {