summaryrefslogtreecommitdiffstats
path: root/src/insexpand.c
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2021-12-31 12:59:53 +0000
committerBram Moolenaar <Bram@vim.org>2021-12-31 12:59:53 +0000
commit6ad84ab3e48d9490e4139df04f2c55b136f5501d (patch)
tree18ed17aaca9b747046507d308bc16bebffe0b877 /src/insexpand.c
parent1fa3de1ce806ba18ebcc00c6d9a0678a84735463 (diff)
patch 8.2.3953: insert completion code is too complicatedv8.2.3953
Problem: Insert completion code is too complicated. Solution: More refactoring. Move function arguments into a struct. (Yegappan Lakshmanan, closes #9437)
Diffstat (limited to 'src/insexpand.c')
-rw-r--r--src/insexpand.c1165
1 files changed, 603 insertions, 562 deletions
diff --git a/src/insexpand.c b/src/insexpand.c
index aecbf77b46..3cefb39748 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -134,6 +134,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;
@@ -227,8 +228,7 @@ ins_ctrl_x(void)
{
if (!ctrl_x_mode_cmdline())
{
- // if the next ^X<> won't ADD nothing, then reset
- // compl_cont_status
+ // if the next ^X<> won't ADD nothing, then reset compl_cont_status
if (compl_cont_status & CONT_N_ADDS)
compl_cont_status |= CONT_INTRPT;
else
@@ -392,6 +392,16 @@ vim_is_ctrl_x_key(int c)
}
/*
+ * Returns TRUE if the currently shown text is the original text when the
+ * completion began.
+ */
+ static int
+ins_compl_at_original_text(compl_T *match)
+{
+ return match->cp_flags & CP_ORIGINAL_TEXT;
+}
+
+/*
* Return TRUE when character "c" is part of the item currently being
* completed. Used to decide whether to abandon complete mode when the menu
* is visible.
@@ -426,6 +436,111 @@ ins_compl_accept_char(int 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)
+{
+ int *wca; // Wide character array.
+ char_u *p;
+ int i, c;
+ int has_lower = FALSE;
+ int was_letter = FALSE;
+
+ IObuff[0] = NUL;
+
+ // Allocate wide character array for the completion and fill it.
+ wca = ALLOC_MULT(int, actual_len);
+ if (wca == NULL)
+ return IObuff;
+
+ p = str;
+ for (i = 0; i < actual_len; ++i)
+ if (has_mbyte)
+ wca[i] = mb_ptr2char_adv(&p);
+ else
+ wca[i] = *(p++);
+
+ // Rule 1: Were any chars converted to lower?
+ p = compl_orig_text;
+ for (i = 0; i < min_len; ++i)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *(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)
+ {
+ p = compl_orig_text;
+ for (i = 0; i < min_len; ++i)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *(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.
+ p = compl_orig_text;
+ for (i = 0; i < min_len; ++i)
+ {
+ if (has_mbyte)
+ c = mb_ptr2char_adv(&p);
+ else
+ c = *(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.
+ p = IObuff;
+ i = 0;
+ while (i < actual_len && (p - IObuff + 6) < IOSIZE)
+ if (has_mbyte)
+ p += (*mb_char2bytes)(wca[i++], p);
+ else
+ *(p++) = wca[i++];
+ *p = NUL;
+
+ vim_free(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
@@ -442,13 +557,9 @@ ins_compl_add_infercase(
{
char_u *str = str_arg;
char_u *p;
- int i, c;
int actual_len; // Take multi-byte characters
int actual_compl_length; // into account.
int min_len;
- int *wca; // Wide character array.
- int has_lower = FALSE;
- int was_letter = FALSE;
int flags = 0;
if (p_ic && curbuf->b_p_inf && len > 0)
@@ -488,91 +599,8 @@ ins_compl_add_infercase(
min_len = actual_len < actual_compl_length
? actual_len : actual_compl_length;
- // Allocate wide character array for the completion and fill it.
- wca = ALLOC_MULT(int, actual_len);
- if (wca != NULL)
- {
- p = str;
- for (i = 0; i < actual_len; ++i)
- if (has_mbyte)
- wca[i] = mb_ptr2char_adv(&p);
- else
- wca[i] = *(p++);
-
- // Rule 1: Were any chars converted to lower?
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i)
- {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(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)
- {
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i)
- {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(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.
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i)
- {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(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.
- p = IObuff;
- i = 0;
- while (i < actual_len && (p - IObuff + 6) < IOSIZE)
- if (has_mbyte)
- p += (*mb_char2bytes)(wca[i++], p);
- else
- *(p++) = wca[i++];
- *p = NUL;
-
- vim_free(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;
@@ -618,7 +646,7 @@ ins_compl_add(
match = compl_first_match;
do
{
- if ( !(match->cp_flags & CP_ORIGINAL_TEXT)
+ if (!ins_compl_at_original_text(match)
&& STRNCMP(match->cp_str, str, len) == 0
&& match->cp_str[len] == NUL)
return NOTDONE;
@@ -730,69 +758,69 @@ ins_compl_longest_match(compl_T *match)
{
// First match, use it as a whole.
compl_leader = vim_strsave(match->cp_str);
- if (compl_leader != NULL)
- {
- had_match = (curwin->w_cursor.col > compl_col);
+ if (compl_leader == NULL)
+ return;
+
+ had_match = (curwin->w_cursor.col > compl_col);
+ ins_compl_delete();
+ ins_bytes(compl_leader + ins_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();
- ins_bytes(compl_leader + ins_compl_len());
- ins_redraw(FALSE);
+ compl_used_match = 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;
- }
+ return;
}
- else
+
+ // Reduce the text if this match differs from compl_leader.
+ p = compl_leader;
+ s = match->cp_str;
+ while (*p != NUL)
{
- // Reduce the text if this match differs from compl_leader.
- p = compl_leader;
- s = match->cp_str;
- while (*p != NUL)
+ if (has_mbyte)
{
- if (has_mbyte)
- {
- c1 = mb_ptr2char(p);
- c2 = mb_ptr2char(s);
- }
- else
- {
- c1 = *p;
- c2 = *s;
- }
- if ((match->cp_flags & CP_ICASE)
- ? (MB_TOLOWER(c1) != MB_TOLOWER(c2)) : (c1 != c2))
- break;
- if (has_mbyte)
- {
- MB_PTR_ADV(p);
- MB_PTR_ADV(s);
- }
- else
- {
- ++p;
- ++s;
- }
+ c1 = mb_ptr2char(p);
+ c2 = mb_ptr2char(s);
}
-
- if (*p != NUL)
+ else
{
- // 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 + ins_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();
+ c1 = *p;
+ c2 = *s;
}
+ if ((match->cp_flags & CP_ICASE)
+ ? (MB_TOLOWER(c1) != MB_TOLOWER(c2)) : (c1 != c2))
+ break;
+ if (has_mbyte)
+ {
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(s);
+ }
+ else
+ {
+ ++p;
+ ++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 + ins_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;
}
/*
@@ -827,19 +855,20 @@ ins_compl_make_cyclic(void)
compl_T *match;
int count = 0;
- if (compl_first_match != NULL)
+ if (compl_first_match == NULL)
+ return 0;
+
+ // 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)
{
- // 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;
+ match = match->cp_next;
+ ++count;
}
+ match->cp_next = compl_first_match;
+ compl_first_match->cp_prev = match;
+
return count;
}
@@ -892,14 +921,14 @@ ins_compl_upd_pum(void)
{
int h;
- if (compl_match_array != NULL)
- {
- h = curwin->w_cline_height;
- // Update the screen later, before drawing the popup menu over it.
- pum_call_update_screen();
- if (h != curwin->w_cline_height)
- ins_compl_del_pum();
- }
+ if (compl_match_array == NULL)
+ return;
+
+ h = curwin->w_cline_height;
+ // Update the screen later, before drawing the popup menu over it.
+ pum_call_update_screen();
+ if (h != curwin->w_cline_height)
+ ins_compl_del_pum();
}
/*
@@ -908,11 +937,11 @@ ins_compl_upd_pum(void)
static void
ins_compl_del_pum(void)
{
- if (compl_match_array != NULL)
- {
- pum_undisplay();
- VIM_CLEAR(compl_match_array);
- }
+ if (compl_match_array == NULL)
+ return;
+
+ pum_undisplay();
+ VIM_CLEAR(compl_match_array);
}
/*
@@ -952,7 +981,7 @@ pum_enough_matches(void)
do
{
if (compl == NULL
- || ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2))
+ || (!ins_compl_at_original_text(compl) && ++i == 2))
break;
compl = compl->cp_next;
} while (compl != compl_first_match);
@@ -972,18 +1001,19 @@ ins_compl_dict_alloc(compl_T *match)
{
dict_T *dict = dict_alloc_lock(VAR_FIXED);
- if (dict != NULL)
- {
- dict_add_string(dict, "word", match->cp_str);
- dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]);
- dict_add_string(dict, "menu", match->cp_text[CPT_MENU]);
- dict_add_string(dict, "kind", match->cp_text[CPT_KIND]);
- dict_add_string(dict, "info", match->cp_text[CPT_INFO]);
- if (match->cp_user_data.v_type == VAR_UNKNOWN)
- dict_add_string(dict, "user_data", (char_u *)"");
- else
- dict_add_tv(dict, "user_data", &match->cp_user_data);
- }
+ if (dict == NULL)
+ return NULL;
+
+ dict_add_string(dict, "word", match->cp_str);
+ dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]);
+ dict_add_string(dict, "menu", match->cp_text[CPT_MENU]);
+ dict_add_string(dict, "kind", match->cp_text[CPT_KIND]);
+ dict_add_string(dict, "info", match->cp_text[CPT_INFO]);
+ if (match->cp_user_data.v_type == VAR_UNKNOWN)
+ dict_add_string(dict, "user_data", (char_u *)"");
+ else
+ dict_add_tv(dict, "user_data", &match->cp_user_data);
+
return dict;
}
@@ -1020,11 +1050,12 @@ trigger_complete_changed_event(int cur)
#endif
/*
- * Show the popup menu for the list of matches.
- * Also adjusts "compl_shown_match" to an entry that is actually displayed.
+ * Build a popup menu to show the completion matches.
+ * Returns the popup menu entry that should be selected. Returns -1 if nothing
+ * should be selected.
*/
- void
-ins_compl_show_pum(void)
+ static int
+ins_compl_build_pum(void)
{
compl_T *compl;
compl_T *shown_compl = NULL;
@@ -1032,108 +1063,125 @@ ins_compl_show_pum(void)
int shown_match_ok = FALSE;
int i;
int cur = -1;
- colnr_T col;
int lead_len = 0;
- if (!pum_wanted() || !pum_enough_matches())
- return;
+ // Need to build the popup menu list.
+ compl_match_arraysize = 0;
+ compl = compl_first_match;
+ if (compl_leader != NULL)
+ lead_len = (int)STRLEN(compl_leader);
-#if defined(FEAT_EVAL)
- // Dirty hard-coded hack: remove any matchparen highlighting.
- do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|:3match none|endif");
-#endif
+ do
+ {
+ if (!ins_compl_at_original_text(compl)
+ && (compl_leader == NULL
+ || ins_compl_equal(compl, compl_leader, lead_len)))
+ ++compl_match_arraysize;
+ compl = compl->cp_next;
+ } while (compl != NULL && compl != compl_first_match);
- // Update the screen later, before drawing the popup menu over it.
- pum_call_update_screen();
+ if (compl_match_arraysize == 0)
+ return -1;
+ compl_match_array = ALLOC_CLEAR_MULT(pumitem_T, compl_match_arraysize);
if (compl_match_array == NULL)
+ return -1;
+
+ // If the current match is the original text don't find the first
+ // match after it, don't highlight anything.
+ if (ins_compl_at_original_text(compl_shown_match))
+ shown_match_ok = TRUE;
+
+ i = 0;
+ compl = compl_first_match;
+ do
{
- // Need to build the popup menu list.
- compl_match_arraysize = 0;
- compl = compl_first_match;
- if (compl_leader != NULL)
- lead_len = (int)STRLEN(compl_leader);
- do
+ if (!ins_compl_at_original_text(compl)
+ && (compl_leader == NULL
+ || ins_compl_equal(compl, compl_leader, lead_len)))
{
- if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
- && (compl_leader == NULL
- || ins_compl_equal(compl, compl_leader, lead_len)))
- ++compl_match_arraysize;
- compl = compl->cp_next;
- } while (compl != NULL && compl != compl_first_match);
- if (compl_match_arraysize == 0)
- return;
- compl_match_array = ALLOC_CLEAR_MULT(pumitem_T, compl_match_arraysize);
- if (compl_match_array != NULL)
+ if (!shown_match_ok)
+ {
+ if (compl == compl_shown_match || did_find_shown_match)
+ {
+ // This item is the shown match or this is the
+ // first displayed item after the shown match.
+ compl_shown_match = compl;
+ did_find_shown_match = TRUE;
+ shown_match_ok = TRUE;
+ }
+ else
+ // Remember this displayed match for when the
+ // shown match is just below it.
+ shown_compl = compl;
+ cur = i;
+ }
+
+ if (compl->cp_text[CPT_ABBR] != NULL)
+ compl_match_array[i].pum_text =
+ compl->cp_text[CPT_ABBR];
+ else
+ compl_match_array[i].pum_text = compl->cp_str;
+ compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
+ compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
+ if (compl->cp_text[CPT_MENU] != NULL)
+ compl_match_array[i++].pum_extra =
+ compl->cp_text[CPT_MENU];
+ else
+ compl_match_array[i++].pum_extra = compl->cp_fname;
+ }
+
+ if (compl == compl_shown_match)
{
- // 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)
+ did_find_shown_match = TRUE;
+
+ // When the original text is the shown match don't set
+ // compl_shown_match.
+ if (ins_compl_at_original_text(compl))
shown_match_ok = TRUE;
- i = 0;
- compl = compl_first_match;
- do
+ if (!shown_match_ok && shown_compl != NULL)
{
- if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
- && (compl_leader == NULL
- || ins_compl_equal(compl, compl_leader, lead_len)))
- {
- if (!shown_match_ok)
- {
- if (compl == compl_shown_match || did_find_shown_match)
- {
- // This item is the shown match or this is the
- // first displayed item after the shown match.
- compl_shown_match = compl;
- did_find_shown_match = TRUE;
- shown_match_ok = TRUE;
- }
- else
- // Remember this displayed match for when the
- // shown match is just below it.
- shown_compl = compl;
- cur = i;
- }
+ // The shown match isn't displayed, set it to the
+ // previously displayed match.
+ compl_shown_match = shown_compl;
+ shown_match_ok = TRUE;
+ }
+ }
+ compl = compl->cp_next;
+ } while (compl != NULL && compl != compl_first_match);
- if (compl->cp_text[CPT_ABBR] != NULL)
- compl_match_array[i].pum_text =
- compl->cp_text[CPT_ABBR];
- else
- compl_match_array[i].pum_text = compl->cp_str;
- compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
- compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
- if (compl->cp_text[CPT_MENU] != NULL)
- compl_match_array[i++].pum_extra =
- compl->cp_text[CPT_MENU];
- else
- compl_match_array[i++].pum_extra = compl->cp_fname;
- }
+ if (!shown_match_ok) // no displayed match at all
+ cur = -1;
- if (compl == compl_shown_match)
- {
- did_find_shown_match = TRUE;
+ return cur;
+}
- // When the original text is the shown match don't set
- // compl_shown_match.
- if (compl->cp_flags & CP_ORIGINAL_TEXT)
- shown_match_ok = TRUE;
+/*
+ * Show the popup menu for the list of matches.
+ * Also adjusts "compl_shown_match" to an entry that is actually displayed.
+ */
+ void
+ins_compl_show_pum(void)
+{
+ int i;
+ int cur = -1;
+ colnr_T col;
- if (!shown_match_ok && shown_compl != NULL)
- {
- // The shown match isn't displayed, set it to the
- // previously displayed match.
- compl_shown_match = shown_compl;
- shown_match_ok = TRUE;
- }
- }
- compl = compl->cp_next;
- } while (compl != NULL && compl != compl_first_match);
+ if (!pum_wanted() || !pum_enough_matches())
+ return;
- if (!shown_match_ok) // no displayed match at all
- cur = -1;
- }
- }
+#if defined(FEAT_EVAL)
+ // Dirty hard-coded hack: remove any matchparen highlighting.
+ do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|:3match none|endif");
+#endif
+
+ // Update the screen later, before drawing the popup menu over it.
+ pum_call_update_screen();
+
+ if (compl_match_array == NULL)
+ // Need to build the popup menu list.
+ cur = ins_compl_build_pum();
else
{
// popup menu already exists, only need to find the current item.
@@ -1147,24 +1195,24 @@ ins_compl_show_pum(void)
}
}
- if (compl_match_array != NULL)
- {
- // In Replace mode when a $ is displayed at the end of the line only
- // part of the screen would be updated. We do need to redraw here.
- dollar_vcol = -1;
+ if (compl_match_array == NULL)
+ return;
+
+ // In Replace mode when a $ is displayed at the end of the line only
+ // part of the screen would be updated. We do need to redraw here.
+ dollar_vcol = -1;
- // Compute the screen column of the start of the completed text.
- // Use the cursor to get all wrapping and other settings right.
- col = curwin->w_cursor.col;
- curwin->w_cursor.col = compl_col;
- pum_display(compl_match_array, compl_match_arraysize, cur);
- curwin->w_cursor.col = col;
+ // Compute the screen column of the start of the completed text.
+ // Use the cursor to get all wrapping and other settings right.
+ col = curwin->w_cursor.col;
+ curwin->w_cursor.col = compl_col;
+ pum_display(compl_match_array, compl_match_arraysize, cur);
+ curwin->w_cursor.col = col;
#ifdef FEAT_EVAL
- if (has_completechanged())
- trigger_complete_changed_event(cur);
+ if (has_completechanged())
+ trigger_complete_changed_event(cur);
#endif
- }
}
#define DICT_FIRST (1) // use just first element in "dict"
@@ -1324,77 +1372,76 @@ ins_compl_files(
(void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
}
- if (fp != NULL)
+ if (fp == NULL)
+ continue;
+
+ // Read dictionary file line by line.
+ // Check each line for a match.
+ while (!got_int && !compl_interrupted && !vim_fgets(buf, LSIZE, fp))
{
- // Read dictionary file line by line.
- // Check each line for a match.
- while (!got_int && !compl_interrupted
- && !vim_fgets(buf, LSIZE, fp))
+ ptr = buf;
+ while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
{
- ptr = buf;
- while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
+ ptr = regmatch->startp[0];
+ if (ctrl_x_mode_line_or_eval())
+ ptr = find_line_end(ptr);
+ else
+ ptr = find_word_end(ptr);
+ add_r = ins_compl_add_infercase(regmatch->startp[0],
+ (int)(ptr - regmatch->startp[0]),
+ p_ic, files[i], *dir, FALSE);
+ if (thesaurus)
{
- ptr = regmatch->startp[0];
- if (ctrl_x_mode_line_or_eval())
- ptr = find_line_end(ptr);
- else
- ptr = find_word_end(ptr);
- add_r = ins_compl_add_infercase(regmatch->startp[0],
- (int)(ptr - regmatch->startp[0]),
- p_ic, files[i], *dir, FALSE);
- if (thesaurus)
+ char_u *wstart;
+
+ // Add the other matches on the line
+ ptr = buf;
+ while (!got_int)
{
- char_u *wstart;
-
- // Add the other matches on the line
- ptr = buf;
- while (!got_int)
- {
- // Find start of the next word. Skip white
- // space and punctuation.
- ptr = find_word_start(ptr);
- if (*ptr == NUL || *ptr == NL)
- break;
- wstart = ptr;
-
- // Find end of the word.
- if (has_mbyte)
- // Japanese words may have characters in
- // different classes, only separate words
- // with single-byte non-word characters.
- while (*ptr != NUL)
- {
- int l = (*mb_ptr2len)(ptr);
-
- if (l < 2 && !vim_iswordc(*ptr))
- break;
- ptr += l;
- }
- else
- ptr = find_word_end(ptr);
-
- // Add the word. Skip the regexp match.
- if (wstart != regmatch->startp[0])
- add_r = ins_compl_add_infercase(wstart,
- (int)(ptr - wstart),
- p_ic, files[i], *dir, FALSE);
- }
+ // Find start of the next word. Skip white
+ // space and punctuation.
+ ptr = find_word_start(ptr);
+ if (*ptr == NUL || *ptr == NL)
+ break;
+ wstart = ptr;
+
+ // Find end of the word.
+ if (has_mbyte)
+ // Japanese words may have characters in
+ // different classes, only separate words
+ // with single-byte non-word characters.
+ while (*ptr != NUL)
+ {
+ int l = (*mb_ptr2len)(ptr);
+
+ if (l < 2 && !vim_iswordc(*ptr))
+ break;
+ ptr += l;
+ }
+ else
+ ptr = find_word_end(ptr);
+
+ // Add the word. Skip the regexp match.
+ if (wstart != regmatch->startp[0])
+ add_r = ins_compl_add_infercase(wstart,
+ (int)(ptr - wstart),
+ p_ic, files[i], *dir, FALSE);
}
- if (add_r == OK)
- // if dir was BACKWARD then honor it just once
- *dir = FORWARD;
- else if (add_r == FAIL)
- break;
- // avoid expensive call to vim_regexec() when at end
- // of line
- if (*ptr == '\n' || got_int)
- break;
}
- line_breakcheck();
- ins_compl_check_keys(50, FALSE);
+ if (add_r == OK)
+ // if dir was BACKWARD then honor it just once
+ *dir = FORWARD;
+ else if (add_r == FAIL)
+ break;
+ // avoid expensive call to vim_regexec() when at end
+ // of line
+ if (*ptr == '\n' || got_int)
+ break;
}
- fclose(fp);
+ line_breakcheck();
+ ins_compl_check_keys(50, FALSE);
}
+ fclose(fp);
}
}
@@ -1757,9 +1804,9 @@ ins_compl_set_original_text(char_u *str)
char_u *p;
// 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 (ins_compl_at_original_text(compl_first_match)) // safety check
{
p = vim_strsave(str);
if (p != NULL)
@@ -1769,7 +1816,7 @@ ins_compl_set_original_text(char_u *str)
}
}
else if (compl_first_match->cp_prev != NULL
- && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT))
+ && ins_compl_at_original_text(compl_first_match->cp_prev))
{
p = vim_strsave(str);
if (p != NULL)
@@ -1797,24 +1844,22 @@ ins_compl_addfrommatch(void)
{
// When still at the original match use the first entry that matches
// the leader.
- if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT)
+ if (!ins_compl_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)
{
- 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,
+ (int)STRLEN(compl_leader)))
{
- if (compl_leader == NULL
- || ins_compl_equal(cp, compl_leader,
- (int)STRLEN(compl_leader)))
- {
- p = cp->cp_str;
- break;
- }
+ p = cp->cp_str;
+ break;
}
- if (p == NULL || (int)STRLEN(p) <= len)
- return;
}
- else
+ if (p == NULL || (int)STRLEN(p) <= len)
return;
}
p += len;
@@ -2860,7 +2905,7 @@ get_complete_info(list_T *what_list, dict_T *retdict)
match = compl_first_match;
do
{
- if (!(match->cp_flags & CP_ORIGINAL_TEXT))
+ if (!ins_compl_at_original_text(match))
{
di = dict_alloc();
if (di == NULL)
@@ -2949,129 +2994,137 @@ enum
};
/*
- * Process the next 'complete' option value in "e_cpt_arg".
+ * state information used for getting the next set of insert completion
+ * matches.
+ */
+typedef struct
+{
+ char_u *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
+ int 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
+ int 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;
+
+/*
+ * 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
*
* Returns INS_COMPL_CPT_OK if the next value is processed successfully.
* Returns INS_COMPL_CPT_CONT to skip the current value and process the next
* option value.
- * Returns INS_COMPL_CPT_END if all the values in "e_cpt" are processed.
+ * Returns INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed.
*/
static int
process_next_cpt_value(
- char_u **e_cpt_arg,
+ ins_compl_next_state_T *st,
int *compl_type_arg,
- int *found_all_arg,
- buf_T **buf_arg,
- pos_T *start_match_pos,
- pos_T *first_match_pos,
- pos_T *last_match_pos,
- int *set_match_pos,
- char_u **dict_arg,
- int *dict_flag)
+ pos_T *start_match_pos)
{
- char_u *e_cpt = *e_cpt_arg;
int compl_type = -1;
int status = INS_COMPL_CPT_OK;
- buf_T *buf = *buf_arg;
- int 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)
+ if (*st->e_cpt == '.' && !curbuf->b_scanned)
{
- buf = curbuf;
- *first_match_pos = *start_match_pos;
+ 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 == CTRL_X_NORMAL && dec(first_match_pos) < 0)
+ if (ctrl_x_mode == CTRL_X_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;
+ st->set_match_pos = TRUE;
}
- else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
- && (buf = ins_compl_next_buf(buf, *e_cpt)) != curbuf)
+ else if (vim_strchr((char_u *)"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 = buf->b_fname;
- dict_f = DICT_EXACT;
+ st->dict = st->ins_buf->b_fname;
+ st->dict_f = DICT_EXACT;
}
msg_hist_off = TRUE; // reset in msg_trunc_attr()