Patch 8.2.3953
Problem: Insert completion code is too complicated.
Solution: More refactoring. Move function arguments into a struct.
(Yegappan Lakshmanan, closes #9437)
Files: src/insexpand.c
*** ../vim-8.2.3952/src/insexpand.c 2021-12-30 11:40:49.936654054 +0000
--- src/insexpand.c 2021-12-31 12:58:29.772742482 +0000
***************
*** 134,139 ****
--- 134,140 ----
* "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,234 ****
{
if (!ctrl_x_mode_cmdline())
{
! // 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
--- 228,234 ----
{
if (!ctrl_x_mode_cmdline())
{
! // 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,397 ****
--- 392,407 ----
}
/*
+ * 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,431 ****
--- 436,546 ----
}
/*
+ * 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,454 ****
{
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)
--- 557,565 ----
***************
*** 488,578 ****
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;
}
if (cont_s_ipos)
flags |= CP_CONT_S_IPOS;
--- 599,606 ----
min_len = actual_len < actual_compl_length
? actual_len : actual_compl_length;
! str = ins_compl_infercase_gettext(str, actual_len, actual_compl_length,
! min_len);
}
if (cont_s_ipos)
flags |= CP_CONT_S_IPOS;
***************
*** 618,624 ****
match = compl_first_match;
do
{
! if ( !(match->cp_flags & CP_ORIGINAL_TEXT)
&& STRNCMP(match->cp_str, str, len) == 0
&& match->cp_str[len] == NUL)
return NOTDONE;
--- 646,652 ----
match = compl_first_match;
do
{
! if (!ins_compl_at_original_text(match)
&& STRNCMP(match->cp_str, str, len) == 0
&& match->cp_str[len] == NUL)
return NOTDONE;
***************
*** 730,798 ****
{
// 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);
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;
! }
}
! else
{
! // Reduce the text if this match differs from compl_leader.
! p = compl_leader;
! s = match->cp_str;
! while (*p != NUL)
{
! 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;
! }
}
!
! 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;
}
}
/*
--- 758,826 ----
{
// First match, use it as a whole.
compl_leader = vim_strsave(match->cp_str);
! 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();
! compl_used_match = FALSE;
! return;
}
!
! // Reduce the text if this match differs from compl_leader.
! p = compl_leader;
! s = match->cp_str;
! while (*p != NUL)
{
! 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;
+ }
+ }
! 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,845 ****
compl_T *match;
int count = 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;
}
return count;
}
--- 855,874 ----
compl_T *match;
int count = 0;
! 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)
{
! match = match->cp_next;
! ++count;
}
+ match->cp_next = compl_first_match;
+ compl_first_match->cp_prev = match;
+
return count;
}
***************
*** 892,905 ****
{
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();
! }
}
/*
--- 921,934 ----
{
int h;
! 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,918 ****
static void
ins_compl_del_pum(void)
{
! if (compl_match_array != NULL)
! {
! pum_undisplay();
! VIM_CLEAR(compl_match_array);
! }
}
/*
--- 937,947 ----
static void
ins_compl_del_pum(void)
{
! if (compl_match_array == NULL)
! return;
!
! pum_undisplay();
! VIM_CLEAR(compl_match_array);
}
/*
***************
*** 952,958 ****
do
{
if (compl == NULL
! || ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2))
break;
compl = compl->cp_next;
} while (compl != compl_first_match);
--- 981,987 ----
do
{
if (compl == NULL
! || (!ins_compl_at_original_text(compl) && ++i == 2))
break;
compl = compl->cp_next;
} while (compl != compl_first_match);
***************
*** 972,989 ****
{
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);
! }
return dict;
}
--- 1001,1019 ----
{
dict_T *dict = dict_alloc_lock(VAR_FIXED);
! 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,1030 ****
#endif
/*
! * 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)
{
compl_T *compl;
compl_T *shown_compl = NULL;
--- 1050,1061 ----
#endif
/*
! * 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.
*/
! static int
! ins_compl_build_pum(void)
{
compl_T *compl;
compl_T *shown_compl = NULL;
***************
*** 1032,1139 ****
int shown_match_ok = FALSE;
int i;
int cur = -1;
- colnr_T col;
int lead_len = 0;
! if (!pum_wanted() || !pum_enough_matches())
! return;
! #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.
! compl_match_arraysize = 0;
! compl = compl_first_match;
! if (compl_leader != NULL)
! lead_len = (int)STRLEN(compl_leader);
! do
{
! 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 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)
shown_match_ok = TRUE;
! i = 0;
! compl = compl_first_match;
! do
{
! 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;
! }
! 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)
! {
! did_find_shown_match = TRUE;
! // 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;
! 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 (!shown_match_ok) // no displayed match at all
! cur = -1;
! }
! }
else
{
// popup menu already exists, only need to find the current item.
--- 1063,1187 ----
int shown_match_ok = FALSE;
int i;
int cur = -1;
int lead_len = 0;
! // 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)))
! ++compl_match_arraysize;
! compl = compl->cp_next;
! } while (compl != NULL && compl != compl_first_match);
! 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
{
! if (!ins_compl_at_original_text(compl)
! && (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;
! }
!
! 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)
{
! 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;
! 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 (!shown_match_ok) // no displayed match at all
! cur = -1;
! return cur;
! }
! /*
! * 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 (!pum_wanted() || !pum_enough_matches())
! return;
! #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,1170 ****
}
}
! 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;
!
! // 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);
#endif
- }
}
#define DICT_FIRST (1) // use just first element in "dict"
--- 1195,1218 ----
}
}
! 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;
#ifdef FEAT_EVAL
! if (has_completechanged())
! trigger_complete_changed_event(cur);
#endif
}
#define DICT_FIRST (1) // use just first element in "dict"
***************
*** 1324,1400 ****
(void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
}
! if (fp != NULL)
{
! // 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 = 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)
! {
! // 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);
}
! fclose(fp);
}
}
}
--- 1372,1447 ----
(void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
}
! 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))
{
! 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)
{
! 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);
}
}
! 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);
}
+ fclose(fp);
}
}
***************
*** 1757,1765 ****
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
{
p = vim_strsave(str);
if (p != NULL)
--- 1804,1812 ----
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 (ins_compl_at_original_text(compl_first_match)) // safety check
{
p = vim_strsave(str);
if (p != NULL)
***************
*** 1769,1775 ****
}
}
else if (compl_first_match->cp_prev != NULL
! && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT))
{
p = vim_strsave(str);
if (p != NULL)
--- 1816,1822 ----
}
}
else if (compl_first_match->cp_prev != NULL
! && ins_compl_at_original_text(compl_first_match->cp_prev))
{
p = vim_strsave(str);
if (p != NULL)
***************
*** 1797,1820 ****
{
// 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,
! (int)STRLEN(compl_leader)))
! {
! p = cp->cp_str;
! break;
! }
}
- if (p == NULL || (int)STRLEN(p) <= len)
- return;
}
! else
return;
}
p += len;
--- 1844,1865 ----
{
// When still at the original match use the first entry that matches
// the leader.
! 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)
! {
! if (compl_leader == NULL
! || ins_compl_equal(cp, compl_leader,
! (int)STRLEN(compl_leader)))
{
! p = cp->cp_str;
! break;
}
}
! if (p == NULL || (int)STRLEN(p) <= len)
return;
}
p += len;
***************
*** 2860,2866 ****
match = compl_first_match;
do
{
! if (!(match->cp_flags & CP_ORIGINAL_TEXT))
{
di = dict_alloc();
if (di == NULL)
--- 2905,2911 ----
match = compl_first_match;
do
{
! if (!ins_compl_at_original_text(match))
{
di = dict_alloc();
if (di == NULL)
***************
*** 2949,3077 ****
};
/*
! * Process the next 'complete' option value in "e_cpt_arg".
*
* If successful, the arguments are set as below:
! * e_cpt_arg - pointer to the next option value in 'e_cpt_arg'
* compl_type_arg - type of insert mode completion to use
! * found_all_arg - all matches of this type are found
! * buf_arg - search for completions in this buffer
! * first_match_pos - position of the first completion match
! * last_match_pos - position of the last completion match
! * set_match_pos - TRUE if the first match position should be saved to avoid
! * loops after the search wraps around.
! * dict - name of the dictionary or thesaurus file to search
! * dict_f - flag specifying whether "dict" is an exact file name or not
*
* 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.
*/
static int
process_next_cpt_value(
! char_u **e_cpt_arg,
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)
{
- 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++;
! if (*e_cpt == '.' && !curbuf->b_scanned)
{
! buf = curbuf;
! *first_match_pos = *start_match_pos;
// Move the cursor back one character so that ^N can match the
// word immediately after the cursor.
! if (ctrl_x_mode == CTRL_X_NORMAL && dec(first_match_pos) < 0)
{
// Move the cursor to after the last character in the
// buffer, so that word at start of buffer is found
// correctly.
! first_match_pos->lnum = buf->b_ml.ml_line_count;
! first_match_pos->col =
! (colnr_T)STRLEN(ml_get(first_match_pos->lnum));
}
! *last_match_pos = *first_match_pos;
compl_type = 0;
// Remember the first match so that the loop stops when we
// wrap and come back there a second time.
! *set_match_pos = TRUE;
}
! else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
! && (buf = ins_compl_next_buf(buf, *e_cpt)) != curbuf)
{
// Scan a buffer, but not the current one.
! if (buf->b_ml.ml_mfp != NULL) // loaded buffer
{
compl_started = TRUE;
! first_match_pos->col = last_match_pos->col = 0;
! first_match_pos->lnum = buf->b_ml.ml_line_count + 1;
! last_match_pos->lnum = 0;
compl_type = 0;
}
else // unloaded buffer, scan like dictionary
{
! found_all = TRUE;
! if (buf->b_fname == NULL)
{
status = INS_COMPL_CPT_CONT;
goto done;
}
compl_type = CTRL_X_DICTIONARY;
! dict = buf->b_fname;
! dict_f = DICT_EXACT;
}
msg_hist_off = TRUE; // reset in msg_trunc_attr()
vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
! buf->b_fname == NULL
! ? buf_spname(buf)
! : buf->b_sfname == NULL
! ? buf->b_fname
! : buf->b_sfname);
(void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
}
! else if (*e_cpt == NUL)
status = INS_COMPL_CPT_END;
else
{
if (ctrl_x_mode_line_or_eval())
compl_type = -1;
! else if (*e_cpt == 'k' || *e_cpt == 's')
{
! if (*e_cpt == 'k')
compl_type = CTRL_X_DICTIONARY;
else
compl_type = CTRL_X_THESAURUS;
! if (*++e_cpt != ',' && *e_cpt != NUL)
{
! dict = e_cpt;
! dict_f = DICT_FIRST;
}
}
#ifdef FEAT_FIND_ID
! else if (*e_cpt == 'i')
compl_type = CTRL_X_PATH_PATTERNS;
! else if (*e_cpt == 'd')
compl_type = CTRL_X_PATH_DEFINES;
#endif
! else if (*e_cpt == ']' || *e_cpt == 't')
{
msg_hist_off = TRUE; // reset in msg_trunc_attr()
compl_type = CTRL_X_TAGS;
--- 2994,3130 ----
};
/*
! * 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:
! * st->cpt - pointer to the next option value in "st->cpt"
* compl_type_arg - type of insert mode completion to use
! * 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 "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)
{
int compl_type = -1;
int status = INS_COMPL_CPT_OK;
! st->found_all = FALSE;
! while (*st->e_cpt == ',' || *st->e_cpt == ' ')
! st->e_cpt++;
!
! 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 == 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.
! 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));
}
! 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.
! st->set_match_pos = TRUE;
}
! 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 (st->ins_buf->b_ml.ml_mfp != NULL) // loaded buffer
{
compl_started = TRUE;
! 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
{
! st->found_all = TRUE;
! if (st->ins_buf->b_fname == NULL)
{
status = INS_COMPL_CPT_CONT;
goto done;
}
compl_type = CTRL_X_DICTIONARY;
! st->dict = 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"),
! 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 (*st->e_cpt == NUL)
status = INS_COMPL_CPT_END;
else
{
if (ctrl_x_mode_line_or_eval())
compl_type = -1;
! 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 (*++st->e_cpt != ',' && *st->e_cpt != NUL)
{
! st->dict = st->e_cpt;
! st->dict_f = DICT_FIRST;
}
}
#ifdef FEAT_FIND_ID
! else if (*st->e_cpt == 'i')
compl_type = CTRL_X_PATH_PATTERNS;
! else if (*st->e_cpt == 'd')
compl_type = CTRL_X_PATH_DEFINES;
#endif
! else if (*st->e_cpt == ']' || *st->e_cpt == 't')
{
msg_hist_off = TRUE; // reset in msg_trunc_attr()
compl_type = CTRL_X_TAGS;
***************
*** 3082,3101 ****
compl_type = -1;
// in any case e_cpt is advanced to the next entry
! (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
! found_all = TRUE;
if (compl_type == -1)
status = INS_COMPL_CPT_CONT;
}
done:
- *e_cpt_arg = e_cpt;
*compl_type_arg = compl_type;
- *found_all_arg = found_all;
- *buf_arg = buf;
- *dict_arg = dict;
- *dict_flag = dict_f;
return status;
}
--- 3135,3149 ----
compl_type = -1;
// in any case e_cpt is advanced to the next entry
! (void)copy_option_part(&st->e_cpt, IObuff, IOSIZE, ",");
! st->found_all = TRUE;
if (compl_type == -1)
status = INS_COMPL_CPT_CONT;
}
done:
*compl_type_arg = compl_type;
return status;
}
***************
*** 3121,3127 ****
* thesaurus files.
*/
static void
! get_next_dict_tsr_completion(int compl_type, char_u **dict, int dict_f)
{
#ifdef FEAT_COMPL_FUNC
if (thesaurus_func_complete(compl_type))
--- 3169,3175 ----
* thesaurus files.
*/
static void
! get_next_dict_tsr_completion(int compl_type, char_u *dict, int dict_f)
{
#ifdef FEAT_COMPL_FUNC
if (thesaurus_func_complete(compl_type))
***************
*** 3129,3142 ****
else
#endif
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)),
compl_pattern,
! *dict != NULL ? dict_f : 0,
compl_type == CTRL_X_THESAURUS);
- *dict = NULL;
}
/*
--- 3177,3189 ----
else
#endif
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)),
compl_pattern,
! dict != NULL ? dict_f : 0,
compl_type == CTRL_X_THESAURUS);
}
/*
***************
*** 3335,3355 ****
/*
* 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".
* Returns OK if a new next match is found, otherwise returns FAIL.
*/
static int
! get_next_default_completion(
! buf_T *ins_buf, // buffer being scanned
! pos_T *start_pos, // search start position
! pos_T *cur_match_pos, // current match position
! pos_T *prev_match_pos, // previous match position
! int *save_match_pos, // set first_match_pos/last_match_pos
! pos_T *first_match_pos, // first match position
! pos_T *last_match_pos, // last match position
! int scan_curbuf) // scan current buffer for completion
{
int found_new_match = FAIL;
int save_p_scs;
--- 3382,3395 ----
/*
* 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 "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".
* Returns OK if a new next match is found, otherwise returns FAIL.
*/
static int
! get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
{
int found_new_match = FAIL;
int save_p_scs;
***************
*** 3360,3366 ****
// If 'infercase' is set, don't use 'smartcase' here
save_p_scs = p_scs;
! if (ins_buf->b_p_inf)
p_scs = FALSE;
// Buffers other than curbuf are scanned from the beginning or the
--- 3400,3406 ----
// If 'infercase' is set, don't use 'smartcase' here
save_p_scs = p_scs;
! if (st->ins_buf->b_p_inf)
p_scs = FALSE;
// Buffers other than curbuf are scanned from the beginning or the
***************
*** 3368,3376 ****
// buffer is a good idea, on the other hand, we always set
// wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
save_p_ws = p_ws;
! if (ins_buf != curbuf)
p_ws = FALSE;
! else if (scan_curbuf)
p_ws = TRUE;
looped_around = FALSE;
for (;;)
--- 3408,3416 ----
// buffer is a good idea, on the other hand, we always set
// wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
save_p_ws = p_ws;
! if (st->ins_buf != curbuf)
p_ws = FALSE;
! else if (*st->e_cpt == '.')
p_ws = TRUE;
looped_around = FALSE;
for (;;)
***************
*** 3383,3413 ****
// has added a word that was at the beginning of the line
if (ctrl_x_mode_line_or_eval()
|| (compl_cont_status & CONT_SOL))
! found_new_match = search_for_exact_line(ins_buf, cur_match_pos,
! compl_direction, compl_pattern);
else
! found_new_match = searchit(NULL, ins_buf, cur_match_pos, NULL,
! compl_direction,
! compl_pattern, 1L, SEARCH_KEEP + SEARCH_NFMSG,
! RE_LAST, NULL);
--msg_silent;
! if (!compl_started || *save_match_pos)
{
// set "compl_started" even on fail
compl_started = TRUE;
! *first_match_pos = *cur_match_pos;
! *last_match_pos = *cur_match_pos;
! *save_match_pos = FALSE;
}
! else if (first_match_pos->lnum == last_match_pos->lnum
! && first_match_pos->col == last_match_pos->col)
{
found_new_match = FAIL;
}
else if ((compl_direction == FORWARD)
! && (prev_match_pos->lnum > cur_match_pos->lnum
! || (prev_match_pos->lnum == cur_match_pos->lnum
! && prev_match_pos->col >= cur_match_pos->col)))
{
if (looped_around)
found_new_match = FAIL;
--- 3423,3452 ----
// 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(st->ins_buf,
! st->cur_match_pos, compl_direction, compl_pattern);
else
! found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
! NULL, compl_direction, compl_pattern, 1L,
! SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
--msg_silent;
! if (!compl_started || st->set_match_pos)
{
// set "compl_started" even on fail
compl_started = TRUE;
! 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)
! && (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;
***************
*** 3415,3446 ****
looped_around = TRUE;
}
else if ((compl_direction != FORWARD)
! && (prev_match_pos->lnum < cur_match_pos->lnum
! || (prev_match_pos->lnum == cur_match_pos->lnum
! && prev_match_pos->col <= cur_match_pos->col)))
{
if (looped_around)
found_new_match = FAIL;
else
looped_around = TRUE;
}
! *prev_match_pos = *cur_match_pos;
if (found_new_match == FAIL)
break;
// when ADDING, the text before the cursor matches, skip it
! if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
! && start_pos->lnum == cur_match_pos->lnum
! && start_pos->col == cur_match_pos->col)
continue;
! ptr = ins_comp_get_next_word_or_line(ins_buf, cur_match_pos, &len,
! &cont_s_ipos);
if (ptr == NULL)
continue;
if (ins_compl_add_infercase(ptr, len, p_ic,
! ins_buf == curbuf ? NULL : ins_buf->b_sfname,
0, cont_s_ipos) != NOTDONE)
{
found_new_match = OK;
--- 3454,3485 ----
looped_around = TRUE;
}
else if ((compl_direction != FORWARD)
! && (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;
}
! 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) && st->ins_buf == curbuf
! && start_pos->lnum == st->cur_match_pos->lnum
! && start_pos->col == st->cur_match_pos->col)
continue;
! 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,
! st->ins_buf == curbuf ? NULL : st->ins_buf->b_sfname,
0, cont_s_ipos) != NOTDONE)
{
found_new_match = OK;
***************
*** 3454,3459 ****
--- 3493,3562 ----
}
/*
+ * get the next set of completion matches for 'type'.
+ * Returns TRUE if a new match is found. Otherwise returns FALSE.
+ */
+ static int
+ get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini)
+ {
+ int found_new_match = FALSE;
+
+ switch (type)
+ {
+ case -1:
+ break;
+ #ifdef FEAT_FIND_ID
+ case CTRL_X_PATH_PATTERNS:
+ case CTRL_X_PATH_DEFINES:
+ get_next_include_file_completion(type);
+ break;
+ #endif
+
+ 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;
+
+ #ifdef FEAT_COMPL_FUNC
+ case CTRL_X_FUNCTION:
+ case CTRL_X_OMNI:
+ expand_by_function(type, compl_pattern);
+ break;
+ #endif
+
+ 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.
***************
*** 3465,3518 ****
static int
ins_compl_get_exp(pos_T *ini)
{
! static pos_T first_match_pos;
! static pos_T last_match_pos;
! static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
! static int found_all = FALSE; // Found all matches of a
! // certain type.
! static buf_T *ins_buf = NULL; // buffer being scanned
!
! pos_T *pos;
int i;
int found_new_match;
int type = ctrl_x_mode;
- char_u *dict = NULL;
- int dict_f = 0;
- int set_match_pos;
- pos_T prev_pos = {0, 0, 0};
if (!compl_started)
{
! FOR_ALL_BUFFERS(ins_buf)
! ins_buf->b_scanned = 0;
! found_all = FALSE;
! ins_buf = curbuf;
! e_cpt = (compl_cont_status & CONT_LOCAL)
? (char_u *)"." : 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.
compl_old_match = compl_curr_match; // remember the last current match
! pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
// For ^N/^P loop over all the flags/windows/buffers in 'complete'.
for (;;)
{
found_new_match = FAIL;
! 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 == CTRL_X_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);
if (status == INS_COMPL_CPT_END)
break;
--- 3568,3609 ----
static int
ins_compl_get_exp(pos_T *ini)
{
! static ins_compl_next_state_T st;
int i;
int found_new_match;
int type = ctrl_x_mode;
if (!compl_started)
{
! FOR_ALL_BUFFERS(st.ins_buf)
! st.ins_buf->b_scanned = 0;
! st.found_all = FALSE;
! st.ins_buf = curbuf;
! st.e_cpt = (compl_cont_status & CONT_LOCAL)
? (char_u *)"." : 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.
compl_old_match = compl_curr_match; // remember the last current match
! 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;
! 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 == CTRL_X_NORMAL
|| ctrl_x_mode_line_or_eval())
! && (!compl_started || st.found_all))
{
! int status = process_next_cpt_value(&st, &type, ini);
if (status == INS_COMPL_CPT_END)
break;
***************
*** 3525,3582 ****
if (compl_pattern == NULL)
break;
! switch (type)
! {
! case -1:
! break;
! #ifdef FEAT_FIND_ID
! case CTRL_X_PATH_PATTERNS:
! case CTRL_X_PATH_DEFINES:
! get_next_include_file_completion(type);
! break;
! #endif
!
! 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;
!
! #ifdef FEAT_COMPL_FUNC
! case CTRL_X_FUNCTION:
! case CTRL_X_OMNI:
! expand_by_function(type, compl_pattern);
! break;
! #endif
!
! 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;
// 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
--- 3616,3623 ----
if (compl_pattern == NULL)
break;
! // 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
***************
*** 3599,3605 ****
{
// Mark a buffer scanned when it has been scanned completely
if (type == 0 || type == CTRL_X_PATH_PATTERNS)
! ins_buf->b_scanned = TRUE;
compl_started = FALSE;
}
--- 3640,3646 ----
{
// Mark a buffer scanned when it has been scanned completely
if (type == 0 || type == CTRL_X_PATH_PATTERNS)
! st.ins_buf->b_scanned = TRUE;
compl_started = FALSE;
}
***************
*** 3607,3613 ****
compl_started = TRUE;
if ((ctrl_x_mode == CTRL_X_NORMAL || ctrl_x_mode_line_or_eval())
! && *e_cpt == NUL) // Got to end of 'complete'
found_new_match = FAIL;
i = -1; // total of matches, unknown
--- 3648,3654 ----
compl_started = TRUE;
if ((ctrl_x_mode == CTRL_X_NORMAL || ctrl_x_mode_line_or_eval())
! && *st.e_cpt == NUL) // Got to end of 'complete'
found_new_match = FAIL;
i = -1; // total of matches, unknown
***************
*** 3699,3705 ****
// illegal bytes.
if (compl_len < (int)STRLEN(compl_shown_match->cp_str))
ins_bytes(compl_shown_match->cp_str + compl_len);
! if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT)
compl_used_match = FALSE;
else
compl_used_match = TRUE;
--- 3740,3746 ----
// illegal bytes.
if (compl_len < (int)STRLEN(compl_shown_match->cp_str))
ins_bytes(compl_shown_match->cp_str + compl_len);
! if (ins_compl_at_original_text(compl_shown_match))
compl_used_match = FALSE;
else
compl_used_match = TRUE;
***************
*** 3832,3838 ****
}
found_end = FALSE;
}
! if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0
&& compl_leader != NULL
&& !ins_compl_equal(compl_shown_match,
compl_leader, (int)STRLEN(compl_leader)))
--- 3873,3879 ----
}
found_end = FALSE;
}
! if (!ins_compl_at_original_text(compl_shown_match)
&& compl_leader != NULL
&& !ins_compl_equal(compl_shown_match,
compl_leader, (int)STRLEN(compl_leader)))
***************
*** 3891,3897 ****
return -1;
if (compl_leader != NULL
! && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0)
// Update "compl_shown_match" to the actually shown match
ins_compl_update_shown_match();
--- 3932,3938 ----
return -1;
if (compl_leader != NULL
! && !ins_compl_at_original_text(compl_shown_match))
// Update "compl_shown_match" to the actually shown match
ins_compl_update_shown_match();
***************
*** 4661,4667 ****
if (edit_submode_extra == NULL)
{
! if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT)
{
edit_submode_extra = (char_u *)_("Back at original");
edit_submode_highl = HLF_W;
--- 4702,4708 ----
if (edit_submode_extra == NULL)
{
! if (ins_compl_at_original_text(compl_curr_match))
{
edit_submode_extra = (char_u *)_("Back at original");
edit_submode_highl = HLF_W;
*** ../vim-8.2.3952/src/version.c 2021-12-31 12:19:18.739789858 +0000
--- src/version.c 2021-12-31 12:58:08.704766015 +0000
***************
*** 751,752 ****
--- 751,754 ----
{ /* Add new patch number below this line */
+ /**/
+ 3953,
/**/
--
hundred-and-one symptoms of being an internet addict:
168. You have your own domain name.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///