Patch 8.2.3944
Problem: Insert mode completion functions are too long.
Solution: Split up into multiple functions. (Yegappan Lakshmanan,
closes #9431)
Files: src/insexpand.c, src/testdir/test_ins_complete.vim
*** ../vim-8.2.3943/src/insexpand.c 2021-12-30 10:32:21.156298119 +0000
--- src/insexpand.c 2021-12-30 11:37:46.568928853 +0000
***************
*** 1823,1828 ****
--- 1823,2079 ----
}
/*
+ * Set the CTRL-X completion mode based on the key 'c' typed after a CTRL-X.
+ * Uses the global variables: ctrl_x_mode, edit_submode, edit_submode_pre,
+ * compl_cont_mode and compl_cont_status.
+ * Returns TRUE when the character is not to be inserted.
+ */
+ static int
+ set_ctrl_x_mode(int c)
+ {
+ int retval = FALSE;
+
+ switch (c)
+ {
+ case Ctrl_E:
+ case Ctrl_Y:
+ // scroll the window one line up or down
+ ctrl_x_mode = CTRL_X_SCROLL;
+ if (!(State & REPLACE_FLAG))
+ edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
+ else
+ edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
+ edit_submode_pre = NULL;
+ showmode();
+ break;
+ case Ctrl_L:
+ // complete whole line
+ ctrl_x_mode = CTRL_X_WHOLE_LINE;
+ break;
+ case Ctrl_F:
+ // complete filenames
+ ctrl_x_mode = CTRL_X_FILES;
+ break;
+ case Ctrl_K:
+ // complete words from a dictinoary
+ ctrl_x_mode = CTRL_X_DICTIONARY;
+ break;
+ case Ctrl_R:
+ // Register insertion without exiting CTRL-X mode
+ // Simply allow ^R to happen without affecting ^X mode
+ break;
+ case Ctrl_T:
+ // complete words from a thesaurus
+ ctrl_x_mode = CTRL_X_THESAURUS;
+ break;
+ #ifdef FEAT_COMPL_FUNC
+ case Ctrl_U:
+ // user defined completion
+ ctrl_x_mode = CTRL_X_FUNCTION;
+ break;
+ case Ctrl_O:
+ // omni completion
+ ctrl_x_mode = CTRL_X_OMNI;
+ break;
+ #endif
+ case 's':
+ case Ctrl_S:
+ // complete spelling suggestions
+ ctrl_x_mode = CTRL_X_SPELL;
+ #ifdef FEAT_SPELL
+ ++emsg_off; // Avoid getting the E756 error twice.
+ spell_back_to_badword();
+ --emsg_off;
+ #endif
+ break;
+ case Ctrl_RSB:
+ // complete tag names
+ ctrl_x_mode = CTRL_X_TAGS;
+ break;
+ #ifdef FEAT_FIND_ID
+ case Ctrl_I:
+ case K_S_TAB:
+ // complete keywords from included files
+ ctrl_x_mode = CTRL_X_PATH_PATTERNS;
+ break;
+ case Ctrl_D:
+ // complete definitions from included files
+ ctrl_x_mode = CTRL_X_PATH_DEFINES;
+ break;
+ #endif
+ case Ctrl_V:
+ case Ctrl_Q:
+ // complete vim commands
+ ctrl_x_mode = CTRL_X_CMDLINE;
+ break;
+ case Ctrl_Z:
+ // stop completion
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ showmode();
+ retval = TRUE;
+ break;
+ case Ctrl_P:
+ case Ctrl_N:
+ // ^X^P means LOCAL expansion if nothing interrupted (eg we
+ // just started ^X mode, or there were enough ^X's to cancel
+ // the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
+ // do normal expansion when interrupting a different mode (say
+ // ^X^F^X^P or ^P^X^X^P, see below)
+ // nothing changes if interrupting mode 0, (eg, the flag
+ // doesn't change when going to ADDING mode -- Acevedo
+ if (!(compl_cont_status & CONT_INTRPT))
+ compl_cont_status |= CONT_LOCAL;
+ else if (compl_cont_mode != 0)
+ compl_cont_status &= ~CONT_LOCAL;
+ // FALLTHROUGH
+ default:
+ // If we have typed at least 2 ^X's... for modes != 0, we set
+ // compl_cont_status = 0 (eg, as if we had just started ^X
+ // mode).
+ // For mode 0, we set "compl_cont_mode" to an impossible
+ // value, in both cases ^X^X can be used to restart the same
+ // mode (avoiding ADDING mode).
+ // Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
+ // 'complete' and local ^P expansions respectively.
+ // In mode 0 an extra ^X is needed since ^X^P goes to ADDING
+ // mode -- Acevedo
+ if (c == Ctrl_X)
+ {
+ if (compl_cont_mode != 0)
+ compl_cont_status = 0;
+ else
+ compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
+ }
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ showmode();
+ break;
+ }
+
+ return retval;
+ }
+
+ /*
+ * Stop insert completion mode
+ */
+ static int
+ ins_compl_stop(int c, int prev_mode, int retval)
+ {
+ char_u *ptr;
+ #ifdef FEAT_CINDENT
+ int want_cindent;
+ #endif
+
+ // Get here when we have finished typing a sequence of ^N and
+ // ^P or other completion characters in CTRL-X mode. Free up
+ // memory that was used, and make sure we can redo the insert.
+ if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
+ {
+ // If any of the original typed text has been changed, eg when
+ // ignorecase is set, we must add back-spaces to the redo
+ // buffer. We add as few as necessary to delete just the part
+ // of the original text that has changed.
+ // When using the longest match, edited the match or used
+ // CTRL-E then don't use the current match.
+ if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
+ ptr = compl_curr_match->cp_str;
+ else
+ ptr = NULL;
+ ins_compl_fixRedoBufForLeader(ptr);
+ }
+
+ #ifdef FEAT_CINDENT
+ want_cindent = (get_can_cindent() && cindent_on());
+ #endif
+ // When completing whole lines: fix indent for 'cindent'.
+ // Otherwise, break line if it's too long.
+ if (compl_cont_mode == CTRL_X_WHOLE_LINE)
+ {
+ #ifdef FEAT_CINDENT
+ // re-indent the current line
+ if (want_cindent)
+ {
+ do_c_expr_indent();
+ want_cindent = FALSE; // don't do it again
+ }
+ #endif
+ }
+ else
+ {
+ int prev_col = curwin->w_cursor.col;
+
+ // put the cursor on the last char, for 'tw' formatting
+ if (prev_col > 0)
+ dec_cursor();
+ // only format when something was inserted
+ if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E)
+ insertchar(NUL, 0, -1);
+ if (prev_col > 0
+ && ml_get_curline()[curwin->w_cursor.col] != NUL)
+ inc_cursor();
+ }
+
+ // If the popup menu is displayed pressing CTRL-Y means accepting
+ // the selection without inserting anything. When
+ // compl_enter_selects is set the Enter key does the same.
+ if ((c == Ctrl_Y || (compl_enter_selects
+ && (c == CAR || c == K_KENTER || c == NL)))
+ && pum_visible())
+ retval = TRUE;
+
+ // CTRL-E means completion is Ended, go back to the typed text.
+ // but only do this, if the Popup is still visible
+ if (c == Ctrl_E)
+ {
+ ins_compl_delete();
+ if (compl_leader != NULL)
+ ins_bytes(compl_leader + ins_compl_len());
+ else if (compl_first_match != NULL)
+ ins_bytes(compl_orig_text + ins_compl_len());
+ retval = TRUE;
+ }
+
+ auto_format(FALSE, TRUE);
+
+ // Trigger the CompleteDonePre event to give scripts a chance to
+ // act upon the completion before clearing the info, and restore
+ // ctrl_x_mode, so that complete_info() can be used.
+ ctrl_x_mode = prev_mode;
+ ins_apply_autocmds(EVENT_COMPLETEDONEPRE);
+
+ ins_compl_free();
+ compl_started = FALSE;
+ compl_matches = 0;
+ if (!shortmess(SHM_COMPLETIONMENU))
+ msg_clr_cmdline(); // necessary for "noshowmode"
+ ctrl_x_mode = CTRL_X_NORMAL;
+ compl_enter_selects = FALSE;
+ if (edit_submode != NULL)
+ {
+ edit_submode = NULL;
+ showmode();
+ }
+
+ #ifdef FEAT_CMDWIN
+ if (c == Ctrl_C && cmdwin_type != 0)
+ // Avoid the popup menu remains displayed when leaving the
+ // command line window.
+ update_screen(0);
+ #endif
+ #ifdef FEAT_CINDENT
+ // Indent now if a key was typed that is in 'cinkeys'.
+ if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
+ do_c_expr_indent();
+ #endif
+ // Trigger the CompleteDone event to give scripts a chance to act
+ // upon the end of completion.
+ ins_apply_autocmds(EVENT_COMPLETEDONE);
+
+ return retval;
+ }
+
+ /*
* Prepare for Insert mode completion, or stop it.
* Called just after typing a character in Insert mode.
* Returns TRUE when the character is not to be inserted;
***************
*** 1830,1839 ****
int
ins_compl_prep(int c)
{
- char_u *ptr;
- #ifdef FEAT_CINDENT
- int want_cindent;
- #endif
int retval = FALSE;
int prev_mode = ctrl_x_mode;
--- 2081,2086 ----
***************
*** 1910,2022 ****
}
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
- {
// We have just typed CTRL-X and aren't quite sure which CTRL-X mode
// it will be yet. Now we decide.
! switch (c)
! {
! case Ctrl_E:
! case Ctrl_Y:
! ctrl_x_mode = CTRL_X_SCROLL;
! if (!(State & REPLACE_FLAG))
! edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
! else
! edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
! edit_submode_pre = NULL;
! showmode();
! break;
! case Ctrl_L:
! ctrl_x_mode = CTRL_X_WHOLE_LINE;
! break;
! case Ctrl_F:
! ctrl_x_mode = CTRL_X_FILES;
! break;
! case Ctrl_K:
! ctrl_x_mode = CTRL_X_DICTIONARY;
! break;
! case Ctrl_R:
! // Simply allow ^R to happen without affecting ^X mode
! break;
! case Ctrl_T:
! ctrl_x_mode = CTRL_X_THESAURUS;
! break;
! #ifdef FEAT_COMPL_FUNC
! case Ctrl_U:
! ctrl_x_mode = CTRL_X_FUNCTION;
! break;
! case Ctrl_O:
! ctrl_x_mode = CTRL_X_OMNI;
! break;
! #endif
! case 's':
! case Ctrl_S:
! ctrl_x_mode = CTRL_X_SPELL;
! #ifdef FEAT_SPELL
! ++emsg_off; // Avoid getting the E756 error twice.
! spell_back_to_badword();
! --emsg_off;
! #endif
! break;
! case Ctrl_RSB:
! ctrl_x_mode = CTRL_X_TAGS;
! break;
! #ifdef FEAT_FIND_ID
! case Ctrl_I:
! case K_S_TAB:
! ctrl_x_mode = CTRL_X_PATH_PATTERNS;
! break;
! case Ctrl_D:
! ctrl_x_mode = CTRL_X_PATH_DEFINES;
! break;
! #endif
! case Ctrl_V:
! case Ctrl_Q:
! ctrl_x_mode = CTRL_X_CMDLINE;
! break;
! case Ctrl_Z:
! ctrl_x_mode = CTRL_X_NORMAL;
! edit_submode = NULL;
! showmode();
! retval = TRUE;
! break;
! case Ctrl_P:
! case Ctrl_N:
! // ^X^P means LOCAL expansion if nothing interrupted (eg we
! // just started ^X mode, or there were enough ^X's to cancel
! // the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
! // do normal expansion when interrupting a different mode (say
! // ^X^F^X^P or ^P^X^X^P, see below)
! // nothing changes if interrupting mode 0, (eg, the flag
! // doesn't change when going to ADDING mode -- Acevedo
! if (!(compl_cont_status & CONT_INTRPT))
! compl_cont_status |= CONT_LOCAL;
! else if (compl_cont_mode != 0)
! compl_cont_status &= ~CONT_LOCAL;
! // FALLTHROUGH
! default:
! // If we have typed at least 2 ^X's... for modes != 0, we set
! // compl_cont_status = 0 (eg, as if we had just started ^X
! // mode).
! // For mode 0, we set "compl_cont_mode" to an impossible
! // value, in both cases ^X^X can be used to restart the same
! // mode (avoiding ADDING mode).
! // Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
! // 'complete' and local ^P expansions respectively.
! // In mode 0 an extra ^X is needed since ^X^P goes to ADDING
! // mode -- Acevedo
! if (c == Ctrl_X)
! {
! if (compl_cont_mode != 0)
! compl_cont_status = 0;
! else
! compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
! }
! ctrl_x_mode = CTRL_X_NORMAL;
! edit_submode = NULL;
! showmode();
! break;
! }
! }
else if (ctrl_x_mode != CTRL_X_NORMAL)
{
// We're already in CTRL-X mode, do we stay in it?
--- 2157,2165 ----
}
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
// We have just typed CTRL-X and aren't quite sure which CTRL-X mode
// it will be yet. Now we decide.
! retval = set_ctrl_x_mode(c);
else if (ctrl_x_mode != CTRL_X_NORMAL)
{
// We're already in CTRL-X mode, do we stay in it?
***************
*** 2040,2151 ****
if ((ctrl_x_mode == CTRL_X_NORMAL && c != Ctrl_N && c != Ctrl_P
&& c != Ctrl_R && !ins_compl_pum_key(c))
|| ctrl_x_mode == CTRL_X_FINISHED)
! {
! // Get here when we have finished typing a sequence of ^N and
! // ^P or other completion characters in CTRL-X mode. Free up
! // memory that was used, and make sure we can redo the insert.
! if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
! {
! // If any of the original typed text has been changed, eg when
! // ignorecase is set, we must add back-spaces to the redo
! // buffer. We add as few as necessary to delete just the part
! // of the original text that has changed.
! // When using the longest match, edited the match or used
! // CTRL-E then don't use the current match.
! if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
! ptr = compl_curr_match->cp_str;
! else
! ptr = NULL;
! ins_compl_fixRedoBufForLeader(ptr);
! }
!
! #ifdef FEAT_CINDENT
! want_cindent = (get_can_cindent() && cindent_on());
! #endif
! // When completing whole lines: fix indent for 'cindent'.
! // Otherwise, break line if it's too long.
! if (compl_cont_mode == CTRL_X_WHOLE_LINE)
! {
! #ifdef FEAT_CINDENT
! // re-indent the current line
! if (want_cindent)
! {
! do_c_expr_indent();
! want_cindent = FALSE; // don't do it again
! }
! #endif
! }
! else
! {
! int prev_col = curwin->w_cursor.col;
!
! // put the cursor on the last char, for 'tw' formatting
! if (prev_col > 0)
! dec_cursor();
! // only format when something was inserted
! if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E)
! insertchar(NUL, 0, -1);
! if (prev_col > 0
! && ml_get_curline()[curwin->w_cursor.col] != NUL)
! inc_cursor();
! }
!
! // If the popup menu is displayed pressing CTRL-Y means accepting
! // the selection without inserting anything. When
! // compl_enter_selects is set the Enter key does the same.
! if ((c == Ctrl_Y || (compl_enter_selects
! && (c == CAR || c == K_KENTER || c == NL)))
! && pum_visible())
! retval = TRUE;
!
! // CTRL-E means completion is Ended, go back to the typed text.
! // but only do this, if the Popup is still visible
! if (c == Ctrl_E)
! {
! ins_compl_delete();
! if (compl_leader != NULL)
! ins_bytes(compl_leader + ins_compl_len());
! else if (compl_first_match != NULL)
! ins_bytes(compl_orig_text + ins_compl_len());
! retval = TRUE;
! }
!
! auto_format(FALSE, TRUE);
!
! // Trigger the CompleteDonePre event to give scripts a chance to
! // act upon the completion before clearing the info, and restore
! // ctrl_x_mode, so that complete_info() can be used.
! ctrl_x_mode = prev_mode;
! ins_apply_autocmds(EVENT_COMPLETEDONEPRE);
!
! ins_compl_free();
! compl_started = FALSE;
! compl_matches = 0;
! if (!shortmess(SHM_COMPLETIONMENU))
! msg_clr_cmdline(); // necessary for "noshowmode"
! ctrl_x_mode = CTRL_X_NORMAL;
! compl_enter_selects = FALSE;
! if (edit_submode != NULL)
! {
! edit_submode = NULL;
! showmode();
! }
!
! #ifdef FEAT_CMDWIN
! if (c == Ctrl_C && cmdwin_type != 0)
! // Avoid the popup menu remains displayed when leaving the
! // command line window.
! update_screen(0);
! #endif
! #ifdef FEAT_CINDENT
! // Indent now if a key was typed that is in 'cinkeys'.
! if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
! do_c_expr_indent();
! #endif
! // Trigger the CompleteDone event to give scripts a chance to act
! // upon the end of completion.
! ins_apply_autocmds(EVENT_COMPLETEDONE);
! }
}
else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
// Trigger the CompleteDone event to give scripts a chance to act
--- 2183,2189 ----
if ((ctrl_x_mode == CTRL_X_NORMAL && c != Ctrl_N && c != Ctrl_P
&& c != Ctrl_R && !ins_compl_pum_key(c))
|| ctrl_x_mode == CTRL_X_FINISHED)
! retval = ins_compl_stop(c, prev_mode, retval);
}
else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
// Trigger the CompleteDone event to give scripts a chance to act
***************
*** 3199,3204 ****
--- 3237,3338 ----
}
/*
+ * Return the next word or line from buffer "ins_buf" at position
+ * "cur_match_pos" for completion. The length of the match is set in "len".
+ */
+ static char_u *
+ ins_comp_get_next_word_or_line(
+ buf_T *ins_buf, // buffer being scanned
+ pos_T *cur_match_pos, // current match position
+ int *match_len,
+ int *cont_s_ipos) // next ^X<> will set initial_pos
+ {
+ char_u *ptr;
+ int len;
+
+ *match_len = 0;
+ ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, FALSE) +
+ cur_match_pos->col;
+ if (ctrl_x_mode_line_or_eval())
+ {
+ if (compl_cont_status & CONT_ADDING)
+ {
+ if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count)
+ return NULL;
+ ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
+ if (!p_paste)
+ ptr = skipwhite(ptr);
+ }
+ len = (int)STRLEN(ptr);
+ }
+ else
+ {
+ char_u *tmp_ptr = ptr;
+
+ if (compl_cont_status & CONT_ADDING)
+ {
+ tmp_ptr += compl_length;
+ // Skip if already inside a word.
+ if (vim_iswordp(tmp_ptr))
+ return NULL;
+ // Find start of next word.
+ tmp_ptr = find_word_start(tmp_ptr);
+ }
+ // Find end of this word.
+ tmp_ptr = find_word_end(tmp_ptr);
+ len = (int)(tmp_ptr - ptr);
+
+ if ((compl_cont_status & CONT_ADDING) && len == compl_length)
+ {
+ if (cur_match_pos->lnum < ins_buf->b_ml.ml_line_count)
+ {
+ // Try next line, if any. the new word will be
+ // "join" as if the normal command "J" was used.
+ // IOSIZE is always greater than
+ // compl_length, so the next STRNCPY always
+ // works -- Acevedo
+ STRNCPY(IObuff, ptr, len);
+ ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
+ tmp_ptr = ptr = skipwhite(ptr);
+ // Find start of next word.
+ tmp_ptr = find_word_start(tmp_ptr);
+ // Find end of next word.
+ tmp_ptr = find_word_end(tmp_ptr);
+ if (tmp_ptr > ptr)
+ {
+ if (*ptr != ')' && IObuff[len - 1] != TAB)
+ {
+ if (IObuff[len - 1] != ' ')
+ IObuff[len++] = ' ';
+ // IObuf =~ "\k.* ", thus len >= 2
+ if (p_js
+ && (IObuff[len - 2] == '.'
+ || (vim_strchr(p_cpo, CPO_JOINSP)
+ == NULL
+ && (IObuff[len - 2] == '?'
+ || IObuff[len - 2] == '!'))))
+ IObuff[len++] = ' ';
+ }
+ // copy as much as possible of the new word
+ if (tmp_ptr - ptr >= IOSIZE - len)
+ tmp_ptr = ptr + IOSIZE - len - 1;
+ STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
+ len += (int)(tmp_ptr - ptr);
+ *cont_s_ipos = TRUE;
+ }
+ IObuff[len] = NUL;
+ ptr = IObuff;
+ }
+ if (len == compl_length)
+ return NULL;
+ }
+ }
+
+ *match_len = len;
+ return ptr;
+ }
+
+ /*
* 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
***************
*** 3299,3380 ****
&& start_pos->lnum == cur_match_pos->lnum
&& start_pos->col == cur_match_pos->col)
continue;
- ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, FALSE) +
- cur_match_pos->col;
- if (ctrl_x_mode_line_or_eval())
- {
- if (compl_cont_status & CONT_ADDING)
- {
- if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count)
- continue;
- ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
- if (!p_paste)
- ptr = skipwhite(ptr);
- }
- len = (int)STRLEN(ptr);
- }
- else
- {
- char_u *tmp_ptr = ptr;
! if (compl_cont_status & CONT_ADDING)
! {
! tmp_ptr += compl_length;
! // Skip if already inside a word.
! if (vim_iswordp(tmp_ptr))
! continue;
! // Find start of next word.
! tmp_ptr = find_word_start(tmp_ptr);
! }
! // Find end of this word.
! tmp_ptr = find_word_end(tmp_ptr);
! len = (int)(tmp_ptr - ptr);
- if ((compl_cont_status & CONT_ADDING) && len == compl_length)
- {
- if (cur_match_pos->lnum < ins_buf->b_ml.ml_line_count)
- {
- // Try next line, if any. the new word will be
- // "join" as if the normal command "J" was used.
- // IOSIZE is always greater than
- // compl_length, so the next STRNCPY always
- // works -- Acevedo
- STRNCPY(IObuff, ptr, len);
- ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
- tmp_ptr = ptr = skipwhite(ptr);
- // Find start of next word.
- tmp_ptr = find_word_start(tmp_ptr);
- // Find end of next word.
- tmp_ptr = find_word_end(tmp_ptr);
- if (tmp_ptr > ptr)
- {
- if (*ptr != ')' && IObuff[len - 1] != TAB)
- {
- if (IObuff[len - 1] != ' ')
- IObuff[len++] = ' ';
- // IObuf =~ "\k.* ", thus len >= 2
- if (p_js
- && (IObuff[len - 2] == '.'
- || (vim_strchr(p_cpo, CPO_JOINSP)
- == NULL
- && (IObuff[len - 2] == '?'
- || IObuff[len - 2] == '!'))))
- IObuff[len++] = ' ';
- }
- // copy as much as possible of the new word
- if (tmp_ptr - ptr >= IOSIZE - len)
- tmp_ptr = ptr + IOSIZE - len - 1;
- STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
- len += (int)(tmp_ptr - ptr);
- cont_s_ipos = TRUE;
- }
- IObuff[len] = NUL;
- ptr = IObuff;
- }
- if (len == compl_length)
- continue;
- }
- }
if (ins_compl_add_infercase(ptr, len, p_ic,
ins_buf == curbuf ? NULL : ins_buf->b_sfname,
0, cont_s_ipos) != NOTDONE)
--- 3433,3444 ----
&& 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)
***************
*** 3567,3572 ****
--- 3631,3665 ----
}
/*
+ * Update "compl_shown_match" to the actually shown match, it may differ when
+ * "compl_leader" is used to omit some of the matches.
+ */
+ static void
+ ins_compl_update_shown_match(void)
+ {
+ while (!ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader))
+ && compl_shown_match->cp_next != NULL
+ && compl_shown_match->cp_next != compl_first_match)
+ compl_shown_match = compl_shown_match->cp_next;
+
+ // If we didn't find it searching forward, and compl_shows_dir is
+ // backward, find the last match.
+ if (compl_shows_dir == BACKWARD
+ && !ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader))
+ && (compl_shown_match->cp_next == NULL
+ || compl_shown_match->cp_next == compl_first_match))
+ {
+ while (!ins_compl_equal(compl_shown_match,
+ compl_leader, (int)STRLEN(compl_leader))
+ && compl_shown_match->cp_prev != NULL
+ && compl_shown_match->cp_prev != compl_first_match)
+ compl_shown_match = compl_shown_match->cp_prev;
+ }
+ }
+
+ /*
* Delete the old text being completed.
*/
void
***************
*** 3622,3718 ****
}
/*
! * Fill in the next completion in the current direction.
! * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
! * get more completions. If it is FALSE, then we just do nothing when there
! * are no more completions in a given direction. The latter case is used when
! * we are still in the middle of finding completions, to allow browsing
! * through the ones found so far.
! * Return the total number of matches, or -1 if still unknown -- webb.
! *
! * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
! * compl_shown_match here.
! *
! * Note that this function may be called recursively once only. First with
! * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
! * calls this function with "allow_get_expansion" FALSE.
*/
! static int
! ins_compl_next(
! int allow_get_expansion,
! int count, // repeat completion this many times; should
! // be at least 1
! int insert_match, // Insert the newly selected match
! int in_compl_func) // called from complete_check()
{
! int num_matches = -1;
! int todo = count;
! compl_T *found_compl = NULL;
! int found_end = FALSE;
! int advance;
! int started = compl_started;
! // When user complete function return -1 for findstart which is next
! // time of 'always', compl_shown_match become NULL.
! if (compl_shown_match == NULL)
! return -1;
! if (compl_leader != NULL
! && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0)
{
! // Set "compl_shown_match" to the actually shown match, it may differ
! // when "compl_leader" is used to omit some of the matches.
! while (!ins_compl_equal(compl_shown_match,
! compl_leader, (int)STRLEN(compl_leader))
! && compl_shown_match->cp_next != NULL
! && compl_shown_match->cp_next != compl_first_match)
! compl_shown_match = compl_shown_match->cp_next;
!
! // If we didn't find it searching forward, and compl_shows_dir is
! // backward, find the last match.
! if (compl_shows_dir == BACKWARD
! && !ins_compl_equal(compl_shown_match,
! compl_leader, (int)STRLEN(compl_leader))
! && (compl_shown_match->cp_next == NULL
! || compl_shown_match->cp_next == compl_first_match))
! {
! while (!ins_compl_equal(compl_shown_match,
! compl_leader, (int)STRLEN(compl_leader))
! && compl_shown_match->cp_prev != NULL
! && compl_shown_match->cp_prev != compl_first_match)
! compl_shown_match = compl_shown_match->cp_prev;
}
}
! if (allow_get_expansion && insert_match
! && (!(compl_get_longest || compl_restarting) || compl_used_match))
! // Delete old text to be replaced
! ins_compl_delete();
!
! // When finding the longest common text we stick at the original text,
! // don't let CTRL-N or CTRL-P move to the first match.
! advance = count != 1 || !allow_get_expansion || !compl_get_longest;
!
! // When restarting the search don't insert the first match either.
! if (compl_restarting)
! {
! advance = FALSE;
! compl_restarting = FALSE;
! }
- // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
- // around.
while (--todo >= 0)
{
if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
{
compl_shown_match = compl_shown_match->cp_next;
found_end = (compl_first_match != NULL
! && (compl_shown_match->cp_next == compl_first_match
! || compl_shown_match == compl_first_match));
}
else if (compl_shows_dir == BACKWARD
! && compl_shown_match->cp_prev != NULL)
{
found_end = (compl_shown_match == compl_first_match);
compl_shown_match = compl_shown_match->cp_prev;
--- 3715,3788 ----
}
/*
! * show the file name for the completion match (if any). Truncate the file
! * name to avoid a wait for return.
*/
! static void
! ins_compl_show_filename(void)
{
! char *lead = _("match in file");
! int space = sc_col - vim_strsize((char_u *)lead) - 2;
! char_u *s;
! char_u *e;
! if (space <= 0)
! return;
! // We need the tail that fits. With double-byte encoding going
! // back from the end is very slow, thus go from the start and keep
! // the text that fits in "space" between "s" and "e".
! for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e))
{
! space -= ptr2cells(e);
! while (space < 0)
! {
! space += ptr2cells(s);
! MB_PTR_ADV(s);
}
}
+ msg_hist_off = TRUE;
+ vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
+ s > compl_shown_match->cp_fname ? "<" : "", s);
+ msg((char *)IObuff);
+ msg_hist_off = FALSE;
+ redraw_cmdline = FALSE; // don't overwrite!
+ }
! /*
! * Find the next set of matches for completion. Repeat the completion 'todo'
! * times. The number of matches found is returned in 'num_matches'.
! *
! * If "allow_get_expansion" is TRUE, then ins_compl_get_exp() may be called to
! * get more completions. If it is FALSE, then do nothing when there are no more
! * completions in the given direction.
! *
! * If "advance" is TRUE, then completion will move to the first match.
! * Otherwise, the original text will be shown.
! *
! * Returns OK on success and -1 if the number of matches are unknown.
! */
! static int
! find_next_completion_match(
! int allow_get_expansion,
! int todo, // repeat completion this many times
! int advance,
! int *num_matches)
! {
! int found_end = FALSE;
! compl_T *found_compl = NULL;
while (--todo >= 0)
{
if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL)
{
compl_shown_match = compl_shown_match->cp_next;
found_end = (compl_first_match != NULL
! && (compl_shown_match->cp_next == compl_first_match
! || compl_shown_match == compl_first_match));
}
else if (compl_shows_dir == BACKWARD
! && compl_shown_match->cp_prev != NULL)
{
found_end = (compl_shown_match == compl_first_match);
compl_shown_match = compl_shown_match->cp_prev;
***************
*** 3741,3751 ****
}
// Find matches.
! num_matches = ins_compl_get_exp(&compl_startpos);
// handle any pending completions
while (compl_pending != 0 && compl_direction == compl_shows_dir
! && advance)
{
if (compl_pending > 0 && compl_shown_match->cp_next != NULL)
{
--- 3811,3821 ----
}
// Find matches.
! *num_matches = ins_compl_get_exp(&compl_startpos);
// handle any pending completions
while (compl_pending != 0 && compl_direction == compl_shows_dir
! && advance)
{
if (compl_pending > 0 && compl_shown_match->cp_next != NULL)
{
***************
*** 3765,3771 ****
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)))
++todo;
else
// Remember a matching item.
--- 3835,3841 ----
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)))
++todo;
else
// Remember a matching item.
***************
*** 3783,3788 ****
--- 3853,3922 ----
}
}
+ return OK;
+ }
+
+ /*
+ * Fill in the next completion in the current direction.
+ * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
+ * get more completions. If it is FALSE, then we just do nothing when there
+ * are no more completions in a given direction. The latter case is used when
+ * we are still in the middle of finding completions, to allow browsing
+ * through the ones found so far.
+ * Return the total number of matches, or -1 if still unknown -- webb.
+ *
+ * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
+ * compl_shown_match here.
+ *
+ * Note that this function may be called recursively once only. First with
+ * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
+ * calls this function with "allow_get_expansion" FALSE.
+ */
+ static int
+ ins_compl_next(
+ int allow_get_expansion,
+ int count, // repeat completion this many times; should
+ // be at least 1
+ int insert_match, // Insert the newly selected match
+ int in_compl_func) // called from complete_check()
+ {
+ int num_matches = -1;
+ int todo = count;
+ int advance;
+ int started = compl_started;
+
+ // When user complete function return -1 for findstart which is next
+ // time of 'always', compl_shown_match become NULL.
+ if (compl_shown_match == NULL)
+ 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();
+
+ if (allow_get_expansion && insert_match
+ && (!(compl_get_longest || compl_restarting) || compl_used_match))
+ // Delete old text to be replaced
+ ins_compl_delete();
+
+ // When finding the longest common text we stick at the original text,
+ // don't let CTRL-N or CTRL-P move to the first match.
+ advance = count != 1 || !allow_get_expansion || !compl_get_longest;
+
+ // When restarting the search don't insert the first match either.
+ if (compl_restarting)
+ {
+ advance = FALSE;
+ compl_restarting = FALSE;
+ }
+
+ // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
+ // around.
+ if (find_next_completion_match(allow_get_expansion, todo, advance,
+ &num_matches) == -1)
+ return -1;
+
// Insert the text of the new completion, or the compl_leader.
if (compl_no_insert && !started)
{
***************
*** 3836,3871 ****
compl_enter_selects = !insert_match && compl_match_array != NULL;
// Show the file name for the match (if any)
- // Truncate the file name to avoid a wait for return.
if (compl_shown_match->cp_fname != NULL)
! {
! char *lead = _("match in file");
! int space = sc_col - vim_strsize((char_u *)lead) - 2;
! char_u *s;
! char_u *e;
!
! if (space > 0)
! {
! // We need the tail that fits. With double-byte encoding going
! // back from the end is very slow, thus go from the start and keep
! // the text that fits in "space" between "s" and "e".
! for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e))
! {
! space -= ptr2cells(e);
! while (space < 0)
! {
! space += ptr2cells(s);
! MB_PTR_ADV(s);
! }
! }
! msg_hist_off = TRUE;
! vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
! s > compl_shown_match->cp_fname ? "<" : "", s);
! msg((char *)IObuff);
! msg_hist_off = FALSE;
! redraw_cmdline = FALSE; // don't overwrite!
! }
! }
return num_matches;
}
--- 3970,3977 ----
compl_enter_selects = !insert_match && compl_match_array != NULL;
// Show the file name for the match (if any)
if (compl_shown_match->cp_fname != NULL)
! ins_compl_show_filename();
return num_matches;
}
***************
*** 4357,4569 ****
}
/*
! * Do Insert mode completion.
! * Called when character "c" was typed, which has a meaning for completion.
! * Returns OK if completion was done, FAIL if something failed (out of mem).
*/
! int
! ins_complete(int c, int enable_pum)
{
char_u *line;
int startcol = 0; // column where searched text starts
colnr_T curs_col; // cursor column
! int n;
! int save_w_wrow;
! int save_w_leftcol;
! int insert_match;
int save_did_ai = did_ai;
int flags = CP_ORIGINAL_TEXT;
- int line_invalid = FALSE;
! compl_direction = ins_compl_key2dir(c);
! insert_match = ins_compl_use_match(c);
!
! if (!compl_started)
! {
! // First time we hit ^N or ^P (in a row, I mean)
! did_ai = FALSE;
#ifdef FEAT_SMARTINDENT
! did_si = FALSE;
! can_si = FALSE;
! can_si_back = FALSE;
#endif
! if (stop_arrow() == FAIL)
! return FAIL;
! line = ml_get(curwin->w_cursor.lnum);
! curs_col = curwin->w_cursor.col;
! compl_pending = 0;
! // If this same ctrl_x_mode has been interrupted use the text from
! // "compl_startpos" to the cursor as a pattern to add a new word
! // instead of expand the one before the cursor, in word-wise if
! // "compl_startpos" is not in the same line as the cursor then fix it
! // (the line has been split because it was longer than 'tw'). if SOL
! // is set then skip the previous pattern, a word at the beginning of
! // the line has been inserted, we'll look for that -- Acevedo.
! if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
! && compl_cont_mode == ctrl_x_mode)
! {
! // it is a continued search
! compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
! if (ctrl_x_mode == CTRL_X_NORMAL
! || ctrl_x_mode == CTRL_X_PATH_PATTERNS
! || ctrl_x_mode == CTRL_X_PATH_DEFINES)
! {
! if (compl_startpos.lnum != curwin->w_cursor.lnum)
! {
! // line (probably) wrapped, set compl_startpos to the
! // first non_blank in the line, if it is not a wordchar
! // include it to get a better pattern, but then we don't
! // want the "\\<" prefix, check it below
! compl_col = (colnr_T)getwhitecols(line);
! compl_startpos.col = compl_col;
! compl_startpos.lnum = curwin->w_cursor.lnum;
! compl_cont_status &= ~CONT_SOL; // clear SOL if present
! }
! else
! {
! // S_IPOS was set when we inserted a word that was at the
! // beginning of the line, which means that we'll go to SOL
! // mode but first we need to redefine compl_startpos
! if (compl_cont_status & CONT_S_IPOS)
! {
! compl_cont_status |= CONT_SOL;
! compl_startpos.col = (colnr_T)(skipwhite(
! line + compl_length
! + compl_startpos.col) - line);
! }
! compl_col = compl_startpos.col;
! }
! compl_length = curwin->w_cursor.col - (int)compl_col;
! // IObuff is used to add a "word from the next line" would we
! // have enough space? just being paranoid
! #define MIN_SPACE 75
! if (compl_length > (IOSIZE - MIN_SPACE))
! {
! compl_cont_status &= ~CONT_SOL;
! compl_length = (IOSIZE - MIN_SPACE);
! compl_col = curwin->w_cursor.col - compl_length;
! }
! compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
! if (compl_length < 1)
! compl_cont_status &= CONT_LOCAL;
! }
! else if (ctrl_x_mode_line_or_eval())
! compl_cont_status = CONT_ADDING | CONT_N_ADDS;
! else
! compl_cont_status = 0;
! }
! else
! compl_cont_status &= CONT_LOCAL;
! if (!(compl_cont_status & CONT_ADDING)) // normal expansion
! {
! compl_cont_mode = ctrl_x_mode;
! if (ctrl_x_mode != CTRL_X_NORMAL)
! // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
! compl_cont_status = 0;
! compl_cont_status |= CONT_N_ADDS;
! compl_startpos = curwin->w_cursor;
! startcol = (int)curs_col;
! compl_col = 0;
! }
!
! // Work out completion pattern and original text -- webb
! if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL)
! {
! if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
! || thesaurus_func_complete(ctrl_x_mode))
! // restore did_ai, so that adding comment leader works
! did_ai = save_did_ai;
! return FAIL;
! }
! // If "line" was changed while getting completion info get it again.
! if (line_invalid)
! line = ml_get(curwin->w_cursor.lnum);
! if (compl_cont_status & CONT_ADDING)
{
! edit_submode_pre = (char_u *)_(" Adding");
! if (ctrl_x_mode_line_or_eval())
! {
! // Insert a new line, keep indentation but ignore 'comments'.
! char_u *old = curbuf->b_p_com;
! curbuf->b_p_com = (char_u *)"";
! compl_startpos.lnum = curwin->w_cursor.lnum;
! compl_startpos.col = compl_col;
! ins_eol('\r');
! curbuf->b_p_com = old;
! compl_length = 0;
! compl_col = curwin->w_cursor.col;
! }
! }
! else
! {
! edit_submode_pre = NULL;
compl_startpos.col = compl_col;
}
-
- if (compl_cont_status & CONT_LOCAL)
- edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
- else
- edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
-
- // If any of the original typed text has been changed we need to fix
- // the redo buffer.
- ins_compl_fixRedoBufForLeader(NULL);
-
- // Always add completion for the original text.
- vim_free(compl_orig_text);
- compl_orig_text = vim_strnsave(line + compl_col, compl_length);
- if (p_ic)
- flags |= CP_ICASE;
- if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
- -1, NULL, NULL, NULL, 0, flags, FALSE) != OK)
- {
- VIM_CLEAR(compl_pattern);
- VIM_CLEAR(compl_orig_text);
- return FAIL;
- }
-
- // showmode might reset the internal line pointers, so it must
- // be called before line = ml_get(), or when this address is no
- // longer needed. -- Acevedo.
- edit_submode_extra = (char_u *)_("-- Searching...");
- edit_submode_highl = HLF_COUNT;
- showmode();
- edit_submode_extra = NULL;
- out_flush();
}
! else if (insert_match && stop_arrow() == FAIL)
! return FAIL;
!
! compl_shown_match = compl_curr_match;
! compl_shows_dir = compl_direction;
!
! // Find next match (and following matches).
! save_w_wrow = curwin->w_wrow;
! save_w_leftcol = curwin->w_leftcol;
! n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE);
!
! // may undisplay the popup menu
! ins_compl_upd_pum();
! if (n > 1) // all matches have been found
! compl_matches = n;
! compl_curr_match = compl_shown_match;
! compl_direction = compl_shows_dir;
! // Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
! // mode.
! if (got_int && !global_busy)
{
! (void)vgetc();
! got_int = FALSE;
}
// we found no match if the list has only the "compl_orig_text"-entry
if (compl_first_match == compl_first_match->cp_next)
{
--- 4463,4655 ----
}
/*
! * Continue an interrupted completion mode search in "line".
! *
! * If this same ctrl_x_mode has been interrupted use the text from
! * "compl_startpos" to the cursor as a pattern to add a new word instead of
! * expand the one before the cursor, in word-wise if "compl_startpos" is not in
! * the same line as the cursor then fix it (the line has been split because it
! * was longer than 'tw'). if SOL is set then skip the previous pattern, a word
! * at the beginning of the line has been inserted, we'll look for that.
*/
! static void
! ins_compl_continue_search(char_u *line)
! {
! // it is a continued search
! compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
! if (ctrl_x_mode == CTRL_X_NORMAL
! || ctrl_x_mode == CTRL_X_PATH_PATTERNS
! || ctrl_x_mode == CTRL_X_PATH_DEFINES)
! {
! if (compl_startpos.lnum != curwin->w_cursor.lnum)
! {
! // line (probably) wrapped, set compl_startpos to the
! // first non_blank in the line, if it is not a wordchar
! // include it to get a better pattern, but then we don't
! // want the "\\<" prefix, check it below
! compl_col = (colnr_T)getwhitecols(line);
! compl_startpos.col = compl_col;
! compl_startpos.lnum = curwin->w_cursor.lnum;
! compl_cont_status &= ~CONT_SOL; // clear SOL if present
! }
! else
! {
! // S_IPOS was set when we inserted a word that was at the
! // beginning of the line, which means that we'll go to SOL
! // mode but first we need to redefine compl_startpos
! if (compl_cont_status & CONT_S_IPOS)
! {
! compl_cont_status |= CONT_SOL;
! compl_startpos.col = (colnr_T)(skipwhite(
! line + compl_length
! + compl_startpos.col) - line);
! }
! compl_col = compl_startpos.col;
! }
! compl_length = curwin->w_cursor.col - (int)compl_col;
! // IObuff is used to add a "word from the next line" would we
! // have enough space? just being paranoid
! #define MIN_SPACE 75
! if (compl_length > (IOSIZE - MIN_SPACE))
! {
! compl_cont_status &= ~CONT_SOL;
! compl_length = (IOSIZE - MIN_SPACE);
! compl_col = curwin->w_cursor.col - compl_length;
! }
! compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
! if (compl_length < 1)
! compl_cont_status &= CONT_LOCAL;
! }
! else if (ctrl_x_mode_line_or_eval())
! compl_cont_status = CONT_ADDING | CONT_N_ADDS;
! else
! compl_cont_status = 0;
! }
!
! /*
! * start insert mode completion
! */
! static int
! ins_compl_start(void)
{
char_u *line;
int startcol = 0; // column where searched text starts
colnr_T curs_col; // cursor column
! int line_invalid = FALSE;
int save_did_ai = did_ai;
int flags = CP_ORIGINAL_TEXT;
! // First time we hit ^N or ^P (in a row, I mean)
! did_ai = FALSE;
#ifdef FEAT_SMARTINDENT
! did_si = FALSE;
! can_si = FALSE;
! can_si_back = FALSE;
#endif
! if (stop_arrow() == FAIL)
! return FAIL;
! line = ml_get(curwin->w_cursor.lnum);
! curs_col = curwin->w_cursor.col;
! compl_pending = 0;
! if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
! && compl_cont_mode == ctrl_x_mode)
! // this same ctrl-x_mode was interrupted previously. Continue the
! // completion.
! ins_compl_continue_search(line);
! else
! compl_cont_status &= CONT_LOCAL;
! if (!(compl_cont_status & CONT_ADDING)) // normal expansion
! {
! compl_cont_mode = ctrl_x_mode;
! if (ctrl_x_mode != CTRL_X_NORMAL)
! // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
! compl_cont_status = 0;
! compl_cont_status |= CONT_N_ADDS;
! compl_startpos = curwin->w_cursor;
! startcol = (int)curs_col;
! compl_col = 0;
! }
!
! // Work out completion pattern and original text -- webb
! if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL)
! {
! if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
! || thesaurus_func_complete(ctrl_x_mode))
! // restore did_ai, so that adding comment leader works
! did_ai = save_did_ai;
! return FAIL;
! }
! // If "line" was changed while getting completion info get it again.
! if (line_invalid)
! line = ml_get(curwin->w_cursor.lnum);
! if (compl_cont_status & CONT_ADDING)
! {
! edit_submode_pre = (char_u *)_(" Adding");
! if (ctrl_x_mode_line_or_eval())
{
! // Insert a new line, keep indentation but ignore 'comments'.
! char_u *old = curbuf->b_p_com;
! curbuf->b_p_com = (char_u *)"";
! compl_startpos.lnum = curwin->w_cursor.lnum;
compl_startpos.col = compl_col;
+ ins_eol('\r');
+ curbuf->b_p_com = old;
+ compl_length = 0;
+ compl_col = curwin->w_cursor.col;
}
}
! else
! {
! edit_submode_pre = NULL;
! compl_startpos.col = compl_col;
! }
! if (compl_cont_status & CONT_LOCAL)
! edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
! else
! edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
! // If any of the original typed text has been changed we need to fix
! // the redo buffer.
! ins_compl_fixRedoBufForLeader(NULL);
!
! // Always add completion for the original text.
! vim_free(compl_orig_text);
! compl_orig_text = vim_strnsave(line + compl_col, compl_length);
! if (p_ic)
! flags |= CP_ICASE;
! if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
! -1, NULL, NULL, NULL, 0, flags, FALSE) != OK)
{
! VIM_CLEAR(compl_pattern);
! VIM_CLEAR(compl_orig_text);
! return FAIL;
}
+ // showmode might reset the internal line pointers, so it must
+ // be called before line = ml_get(), or when this address is no
+ // longer needed. -- Acevedo.
+ edit_submode_extra = (char_u *)_("-- Searching...");
+ edit_submode_highl = HLF_COUNT;
+ showmode();
+ edit_submode_extra = NULL;
+ out_flush();
+
+ return OK;
+ }
+
+ /*
+ * display the completion status message
+ */
+ static void
+ ins_compl_show_statusmsg(void)
+ {
// we found no match if the list has only the "compl_orig_text"-entry
if (compl_first_match == compl_first_match->cp_next)
{
***************
*** 4571,4593 ****
&& compl_length > 1
? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
edit_submode_highl = HLF_E;
- // remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
- // because we couldn't expand anything at first place, but if we used
- // ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
- // (such as M in M'exico) if not tried already. -- Acevedo
- if ( compl_length > 1
- || (compl_cont_status & CONT_ADDING)
- || (ctrl_x_mode != CTRL_X_NORMAL
- && ctrl_x_mode != CTRL_X_PATH_PATTERNS
- && ctrl_x_mode != CTRL_X_PATH_DEFINES))
- compl_cont_status &= ~CONT_N_ADDS;
}
- if (compl_curr_match->cp_flags & CP_CONT_S_IPOS)
- compl_cont_status |= CONT_S_IPOS;
- else
- compl_cont_status &= ~CONT_S_IPOS;
-
if (edit_submode_extra == NULL)
{
if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT)
--- 4657,4664 ----
***************
*** 4623,4634 ****
if (compl_matches > 0)
vim_snprintf((char *)match_ref, sizeof(match_ref),
! _("match %d of %d"),
! compl_curr_match->cp_number, compl_matches);
else
vim_snprintf((char *)match_ref, sizeof(match_ref),
! _("match %d"),
! compl_curr_match->cp_number);
edit_submode_extra = match_ref;
edit_submode_highl = HLF_R;
if (dollar_vcol >= 0)
--- 4694,4705 ----
if (compl_matches > 0)
vim_snprintf((char *)match_ref, sizeof(match_ref),
! _("match %d of %d"),
! compl_curr_match->cp_number, compl_matches);
else
vim_snprintf((char *)match_ref, sizeof(match_ref),
! _("match %d"),
! compl_curr_match->cp_number);
edit_submode_extra = match_ref;
edit_submode_highl = HLF_R;
if (dollar_vcol >= 0)
***************
*** 4658,4663 ****
--- 4729,4805 ----
msg_clr_cmdline(); // necessary for "noshowmode"
}
}
+ }
+
+ /*
+ * Do Insert mode completion.
+ * Called when character "c" was typed, which has a meaning for completion.
+ * Returns OK if completion was done, FAIL if something failed (out of mem).
+ */
+ int
+ ins_complete(int c, int enable_pum)
+ {
+ int n;
+ int save_w_wrow;
+ int save_w_leftcol;
+ int insert_match;
+
+ compl_direction = ins_compl_key2dir(c);
+ insert_match = ins_compl_use_match(c);
+
+ if (!compl_started)
+ {
+ if (ins_compl_start() == FAIL)
+ return FAIL;
+ }
+ else if (insert_match && stop_arrow() == FAIL)
+ return FAIL;
+
+ compl_shown_match = compl_curr_match;
+ compl_shows_dir = compl_direction;
+
+ // Find next match (and following matches).
+ save_w_wrow = curwin->w_wrow;
+ save_w_leftcol = curwin->w_leftcol;
+ n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE);
+
+ // may undisplay the popup menu
+ ins_compl_upd_pum();
+
+ if (n > 1) // all matches have been found
+ compl_matches = n;
+ compl_curr_match = compl_shown_match;
+ compl_direction = compl_shows_dir;
+
+ // Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
+ // mode.
+ if (got_int && !global_busy)
+ {
+ (void)vgetc();
+ got_int = FALSE;
+ }
+
+ // we found no match if the list has only the "compl_orig_text"-entry
+ if (compl_first_match == compl_first_match->cp_next)
+ {
+ // remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
+ // because we couldn't expand anything at first place, but if we used
+ // ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
+ // (such as M in M'exico) if not tried already. -- Acevedo
+ if (compl_length > 1
+ || (compl_cont_status & CONT_ADDING)
+ || (ctrl_x_mode != CTRL_X_NORMAL
+ && ctrl_x_mode != CTRL_X_PATH_PATTERNS
+ && ctrl_x_mode != CTRL_X_PATH_DEFINES))
+ compl_cont_status &= ~CONT_N_ADDS;
+ }
+
+ if (compl_curr_match->cp_flags & CP_CONT_S_IPOS)
+ compl_cont_status |= CONT_S_IPOS;
+ else
+ compl_cont_status &= ~CONT_S_IPOS;
+
+ ins_compl_show_statusmsg();
// Show the popup menu, unless we got interrupted.
if (enable_pum && !compl_interrupted)
*** ../vim-8.2.3943/src/testdir/test_ins_complete.vim 2021-12-29 17:38:42.301517624 +0000
--- src/testdir/test_ins_complete.vim 2021-12-30 11:37:46.568928853 +0000
***************
*** 900,905 ****
--- 900,924 ----
close!
endfunc
+ " Test for typing CTRL-R in insert completion mode to insert a register
+ " content.
+ func Test_complete_reginsert()
+ new
+ call setline(1, ['a1', 'a12', 'a123', 'a1234'])
+
+ " if a valid CTRL-X mode key is returned from <C-R>=, then it should be
+ " processed. Otherwise, CTRL-X mode should be stopped and the key should be
+ " inserted.
+ exe "normal Goa\<C-P>\<C-R>=\"\\<C-P>\"\<CR>"
+ call assert_equal('a123', getline(5))
+ let @r = "\<C-P>\<C-P>"
+ exe "normal GCa\<C-P>\<C-R>r"
+ call assert_equal('a12', getline(5))
+ exe "normal GCa\<C-P>\<C-R>=\"x\"\<CR>"
+ call assert_equal('a1234x', getline(5))
+ bw!
+ endfunc
+
func Test_issue_7021()
CheckMSWindows
*** ../vim-8.2.3943/src/version.c 2021-12-30 10:51:41.168860630 +0000
--- src/version.c 2021-12-30 11:39:10.808802978 +0000
***************
*** 751,752 ****
--- 751,754 ----
{ /* Add new patch number below this line */
+ /**/
+ 3944,
/**/
--
hundred-and-one symptoms of being an internet addict:
150. You find yourself counting emoticons to get to sleep.
/// 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 ///