mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 11:28:22 +00:00
vim-patch:8.2.3944: insert mode completion functions are too long
Problem: Insert mode completion functions are too long.
Solution: Split up into multiple functions. (Yegappan Lakshmanan,
closes vim/vim#9431)
5d2e007ccb
Cherry-pick can_cindent_get() -> get_can_cindent() from patch 8.1.2062.
This commit is contained in:
@@ -5654,7 +5654,7 @@ static char_u *do_insert_char_pre(int c)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_cindent_get(void)
|
bool get_can_cindent(void)
|
||||||
{
|
{
|
||||||
return can_cindent;
|
return can_cindent;
|
||||||
}
|
}
|
||||||
|
@@ -1650,64 +1650,19 @@ void ins_compl_addfrommatch(void)
|
|||||||
ins_compl_addleader(c);
|
ins_compl_addleader(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare for Insert mode completion, or stop it.
|
/// Set the CTRL-X completion mode based on the key 'c' typed after a CTRL-X.
|
||||||
/// Called just after typing a character in Insert mode.
|
/// Uses the global variables: ctrl_x_mode, edit_submode, edit_submode_pre,
|
||||||
|
/// compl_cont_mode and compl_cont_status.
|
||||||
///
|
///
|
||||||
/// @param c character that was typed
|
/// @return true when the character is not to be inserted.
|
||||||
///
|
static bool set_ctrl_x_mode(const int c)
|
||||||
/// @return true when the character is not to be inserted;
|
|
||||||
bool ins_compl_prep(int c)
|
|
||||||
{
|
{
|
||||||
char_u *ptr;
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
const int prev_mode = ctrl_x_mode;
|
|
||||||
|
|
||||||
// Forget any previous 'special' messages if this is actually
|
|
||||||
// a ^X mode key - bar ^R, in which case we wait to see what it gives us.
|
|
||||||
if (c != Ctrl_R && vim_is_ctrl_x_key(c)) {
|
|
||||||
edit_submode_extra = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore end of Select mode mapping and mouse scroll buttons.
|
|
||||||
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
|
|
||||||
|| c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
|
|
||||||
|| c == K_COMMAND || c == K_LUA) {
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) {
|
|
||||||
if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
|
|
||||||
|| !vim_is_ctrl_x_key(c)) {
|
|
||||||
// Not starting another completion mode.
|
|
||||||
ctrl_x_mode = CTRL_X_CMDLINE;
|
|
||||||
|
|
||||||
// CTRL-X CTRL-Z should stop completion without inserting anything
|
|
||||||
if (c == Ctrl_Z) {
|
|
||||||
retval = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctrl_x_mode = CTRL_X_CMDLINE;
|
|
||||||
|
|
||||||
// Other CTRL-X keys first stop completion, then start another
|
|
||||||
// completion mode.
|
|
||||||
ins_compl_prep(' ');
|
|
||||||
ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set "compl_get_longest" when finding the first matches.
|
|
||||||
if (ctrl_x_mode_not_defined_yet()
|
|
||||||
|| (ctrl_x_mode_normal() && !compl_started)) {
|
|
||||||
compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
|
|
||||||
compl_used_match = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctrl_x_mode_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) {
|
switch (c) {
|
||||||
case Ctrl_E:
|
case Ctrl_E:
|
||||||
case Ctrl_Y:
|
case Ctrl_Y:
|
||||||
|
// scroll the window one line up or down
|
||||||
ctrl_x_mode = CTRL_X_SCROLL;
|
ctrl_x_mode = CTRL_X_SCROLL;
|
||||||
if (!(State & REPLACE_FLAG)) {
|
if (!(State & REPLACE_FLAG)) {
|
||||||
edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
|
edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
|
||||||
@@ -1718,48 +1673,61 @@ bool ins_compl_prep(int c)
|
|||||||
showmode();
|
showmode();
|
||||||
break;
|
break;
|
||||||
case Ctrl_L:
|
case Ctrl_L:
|
||||||
|
// complete whole line
|
||||||
ctrl_x_mode = CTRL_X_WHOLE_LINE;
|
ctrl_x_mode = CTRL_X_WHOLE_LINE;
|
||||||
break;
|
break;
|
||||||
case Ctrl_F:
|
case Ctrl_F:
|
||||||
|
// complete filenames
|
||||||
ctrl_x_mode = CTRL_X_FILES;
|
ctrl_x_mode = CTRL_X_FILES;
|
||||||
break;
|
break;
|
||||||
case Ctrl_K:
|
case Ctrl_K:
|
||||||
|
// complete words from a dictionary
|
||||||
ctrl_x_mode = CTRL_X_DICTIONARY;
|
ctrl_x_mode = CTRL_X_DICTIONARY;
|
||||||
break;
|
break;
|
||||||
case Ctrl_R:
|
case Ctrl_R:
|
||||||
|
// Register insertion without exiting CTRL-X mode
|
||||||
// Simply allow ^R to happen without affecting ^X mode
|
// Simply allow ^R to happen without affecting ^X mode
|
||||||
break;
|
break;
|
||||||
case Ctrl_T:
|
case Ctrl_T:
|
||||||
|
// complete words from a thesaurus
|
||||||
ctrl_x_mode = CTRL_X_THESAURUS;
|
ctrl_x_mode = CTRL_X_THESAURUS;
|
||||||
break;
|
break;
|
||||||
case Ctrl_U:
|
case Ctrl_U:
|
||||||
|
// user defined completion
|
||||||
ctrl_x_mode = CTRL_X_FUNCTION;
|
ctrl_x_mode = CTRL_X_FUNCTION;
|
||||||
break;
|
break;
|
||||||
case Ctrl_O:
|
case Ctrl_O:
|
||||||
|
// omni completion
|
||||||
ctrl_x_mode = CTRL_X_OMNI;
|
ctrl_x_mode = CTRL_X_OMNI;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
case Ctrl_S:
|
case Ctrl_S:
|
||||||
|
// complete spelling suggestions
|
||||||
ctrl_x_mode = CTRL_X_SPELL;
|
ctrl_x_mode = CTRL_X_SPELL;
|
||||||
emsg_off++; // Avoid getting the E756 error twice.
|
emsg_off++; // Avoid getting the E756 error twice.
|
||||||
spell_back_to_badword();
|
spell_back_to_badword();
|
||||||
emsg_off--;
|
emsg_off--;
|
||||||
break;
|
break;
|
||||||
case Ctrl_RSB:
|
case Ctrl_RSB:
|
||||||
|
// complete tag names
|
||||||
ctrl_x_mode = CTRL_X_TAGS;
|
ctrl_x_mode = CTRL_X_TAGS;
|
||||||
break;
|
break;
|
||||||
case Ctrl_I:
|
case Ctrl_I:
|
||||||
case K_S_TAB:
|
case K_S_TAB:
|
||||||
|
// complete keywords from included files
|
||||||
ctrl_x_mode = CTRL_X_PATH_PATTERNS;
|
ctrl_x_mode = CTRL_X_PATH_PATTERNS;
|
||||||
break;
|
break;
|
||||||
case Ctrl_D:
|
case Ctrl_D:
|
||||||
|
// complete definitions from included files
|
||||||
ctrl_x_mode = CTRL_X_PATH_DEFINES;
|
ctrl_x_mode = CTRL_X_PATH_DEFINES;
|
||||||
break;
|
break;
|
||||||
case Ctrl_V:
|
case Ctrl_V:
|
||||||
case Ctrl_Q:
|
case Ctrl_Q:
|
||||||
|
// complete vim commands
|
||||||
ctrl_x_mode = CTRL_X_CMDLINE;
|
ctrl_x_mode = CTRL_X_CMDLINE;
|
||||||
break;
|
break;
|
||||||
case Ctrl_Z:
|
case Ctrl_Z:
|
||||||
|
// stop completion
|
||||||
ctrl_x_mode = CTRL_X_NORMAL;
|
ctrl_x_mode = CTRL_X_NORMAL;
|
||||||
edit_submode = NULL;
|
edit_submode = NULL;
|
||||||
showmode();
|
showmode();
|
||||||
@@ -1803,30 +1771,13 @@ bool ins_compl_prep(int c)
|
|||||||
showmode();
|
showmode();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (ctrl_x_mode_not_default()) {
|
|
||||||
// We're already in CTRL-X mode, do we stay in it?
|
return retval;
|
||||||
if (!vim_is_ctrl_x_key(c)) {
|
|
||||||
if (ctrl_x_mode_scroll()) {
|
|
||||||
ctrl_x_mode = CTRL_X_NORMAL;
|
|
||||||
} else {
|
|
||||||
ctrl_x_mode = CTRL_X_FINISHED;
|
|
||||||
}
|
|
||||||
edit_submode = NULL;
|
|
||||||
}
|
|
||||||
showmode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compl_started || ctrl_x_mode == CTRL_X_FINISHED) {
|
/// Stop insert completion mode
|
||||||
// Show error message from attempted keyword completion (probably
|
static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
|
||||||
// 'Pattern not found') until another key is hit, then go back to
|
{
|
||||||
// showing what mode we are in.
|
|
||||||
showmode();
|
|
||||||
if ((ctrl_x_mode_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
|
// Get here when we have finished typing a sequence of ^N and
|
||||||
// ^P or other completion characters in CTRL-X mode. Free up
|
// ^P or other completion characters in CTRL-X mode. Free up
|
||||||
// memory that was used, and make sure we can redo the insert.
|
// memory that was used, and make sure we can redo the insert.
|
||||||
@@ -1837,6 +1788,7 @@ bool ins_compl_prep(int c)
|
|||||||
// of the original text that has changed.
|
// of the original text that has changed.
|
||||||
// When using the longest match, edited the match or used
|
// When using the longest match, edited the match or used
|
||||||
// CTRL-E then don't use the current match.
|
// CTRL-E then don't use the current match.
|
||||||
|
char_u *ptr;
|
||||||
if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) {
|
if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) {
|
||||||
ptr = compl_curr_match->cp_str;
|
ptr = compl_curr_match->cp_str;
|
||||||
} else {
|
} else {
|
||||||
@@ -1845,7 +1797,7 @@ bool ins_compl_prep(int c)
|
|||||||
ins_compl_fixRedoBufForLeader(ptr);
|
ins_compl_fixRedoBufForLeader(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool want_cindent = (can_cindent_get() && cindent_on());
|
bool want_cindent = (get_can_cindent() && cindent_on());
|
||||||
|
|
||||||
// When completing whole lines: fix indent for 'cindent'.
|
// When completing whole lines: fix indent for 'cindent'.
|
||||||
// Otherwise, break line if it's too long.
|
// Otherwise, break line if it's too long.
|
||||||
@@ -1856,13 +1808,14 @@ bool ins_compl_prep(int c)
|
|||||||
want_cindent = false; // don't do it again
|
want_cindent = false; // don't do it again
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int prev_col = curwin->w_cursor.col;
|
const int prev_col = curwin->w_cursor.col;
|
||||||
|
|
||||||
// put the cursor on the last char, for 'tw' formatting
|
// put the cursor on the last char, for 'tw' formatting
|
||||||
if (prev_col > 0) {
|
if (prev_col > 0) {
|
||||||
dec_cursor();
|
dec_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only format when something was inserted
|
||||||
if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E) {
|
if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E) {
|
||||||
insertchar(NUL, 0, -1);
|
insertchar(NUL, 0, -1);
|
||||||
}
|
}
|
||||||
@@ -1915,9 +1868,9 @@ bool ins_compl_prep(int c)
|
|||||||
showmode();
|
showmode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c == Ctrl_C && cmdwin_type != 0) {
|
||||||
// Avoid the popup menu remains displayed when leaving the
|
// Avoid the popup menu remains displayed when leaving the
|
||||||
// command line window.
|
// command line window.
|
||||||
if (c == Ctrl_C && cmdwin_type != 0) {
|
|
||||||
update_screen(0);
|
update_screen(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1928,6 +1881,90 @@ bool ins_compl_prep(int c)
|
|||||||
// Trigger the CompleteDone event to give scripts a chance to act
|
// Trigger the CompleteDone event to give scripts a chance to act
|
||||||
// upon the end of completion.
|
// upon the end of completion.
|
||||||
ins_apply_autocmds(EVENT_COMPLETEDONE);
|
ins_apply_autocmds(EVENT_COMPLETEDONE);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepare for Insert mode completion, or stop it.
|
||||||
|
/// Called just after typing a character in Insert mode.
|
||||||
|
///
|
||||||
|
/// @param c character that was typed
|
||||||
|
///
|
||||||
|
/// @return true when the character is not to be inserted;
|
||||||
|
bool ins_compl_prep(int c)
|
||||||
|
{
|
||||||
|
bool retval = false;
|
||||||
|
const int prev_mode = ctrl_x_mode;
|
||||||
|
|
||||||
|
// Forget any previous 'special' messages if this is actually
|
||||||
|
// a ^X mode key - bar ^R, in which case we wait to see what it gives us.
|
||||||
|
if (c != Ctrl_R && vim_is_ctrl_x_key(c)) {
|
||||||
|
edit_submode_extra = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore end of Select mode mapping and mouse scroll buttons.
|
||||||
|
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
|
||||||
|
|| c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
|
||||||
|
|| c == K_COMMAND || c == K_LUA) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) {
|
||||||
|
if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
|
||||||
|
|| !vim_is_ctrl_x_key(c)) {
|
||||||
|
// Not starting another completion mode.
|
||||||
|
ctrl_x_mode = CTRL_X_CMDLINE;
|
||||||
|
|
||||||
|
// CTRL-X CTRL-Z should stop completion without inserting anything
|
||||||
|
if (c == Ctrl_Z) {
|
||||||
|
retval = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctrl_x_mode = CTRL_X_CMDLINE;
|
||||||
|
|
||||||
|
// Other CTRL-X keys first stop completion, then start another
|
||||||
|
// completion mode.
|
||||||
|
ins_compl_prep(' ');
|
||||||
|
ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set "compl_get_longest" when finding the first matches.
|
||||||
|
if (ctrl_x_mode_not_defined_yet()
|
||||||
|
|| (ctrl_x_mode_normal() && !compl_started)) {
|
||||||
|
compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
|
||||||
|
compl_used_match = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrl_x_mode_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_not_default()) {
|
||||||
|
// We're already in CTRL-X mode, do we stay in it?
|
||||||
|
if (!vim_is_ctrl_x_key(c)) {
|
||||||
|
if (ctrl_x_mode_scroll()) {
|
||||||
|
ctrl_x_mode = CTRL_X_NORMAL;
|
||||||
|
} else {
|
||||||
|
ctrl_x_mode = CTRL_X_FINISHED;
|
||||||
|
}
|
||||||
|
edit_submode = NULL;
|
||||||
|
}
|
||||||
|
showmode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compl_started || ctrl_x_mode == CTRL_X_FINISHED) {
|
||||||
|
// Show error message from attempted keyword completion (probably
|
||||||
|
// 'Pattern not found') until another key is hit, then go back to
|
||||||
|
// showing what mode we are in.
|
||||||
|
showmode();
|
||||||
|
if ((ctrl_x_mode_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) {
|
} else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
|
||||||
// Trigger the CompleteDone event to give scripts a chance to act
|
// Trigger the CompleteDone event to give scripts a chance to act
|
||||||
@@ -2701,6 +2738,91 @@ static void get_next_spell_completion(linenr_T lnum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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".
|
||||||
|
/// @param ins_buf buffer being scanned
|
||||||
|
/// @param cur_match_pos current match position
|
||||||
|
/// @param match_len
|
||||||
|
/// @param cont_s_ipos next ^X<> will set initial_pos
|
||||||
|
static char_u *ins_comp_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len,
|
||||||
|
bool *cont_s_ipos)
|
||||||
|
{
|
||||||
|
*match_len = 0;
|
||||||
|
char_u *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, false) + cur_match_pos->col;
|
||||||
|
int len;
|
||||||
|
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 = (char_u *)skipwhite((char *)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); // NOLINT(runtime/printf)
|
||||||
|
ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, false);
|
||||||
|
tmp_ptr = ptr = (char_u *)skipwhite((char *)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] == '.'
|
||||||
|
|| 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;
|
||||||
|
}
|
||||||
|
STRLCPY(IObuff + len, ptr, IOSIZE - len);
|
||||||
|
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)
|
/// Get the next set of words matching "compl_pattern" for default completion(s)
|
||||||
/// (normal ^P/^N and ^X^L).
|
/// (normal ^P/^N and ^X^L).
|
||||||
/// Search for "compl_pattern" in the buffer "ins_buf" starting from the
|
/// Search for "compl_pattern" in the buffer "ins_buf" starting from the
|
||||||
@@ -2797,76 +2919,12 @@ static int get_next_default_completion(buf_T *ins_buf, pos_T *start_pos, pos_T *
|
|||||||
&& start_pos->col == cur_match_pos->col) {
|
&& start_pos->col == cur_match_pos->col) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char_u *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, false) + cur_match_pos->col;
|
|
||||||
int len;
|
int len;
|
||||||
if (ctrl_x_mode_line_or_eval()) {
|
char_u *ptr = ins_comp_get_next_word_or_line(ins_buf, cur_match_pos, &len,
|
||||||
if (compl_cont_status & CONT_ADDING) {
|
&cont_s_ipos);
|
||||||
if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) {
|
if (ptr == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, false);
|
|
||||||
if (!p_paste) {
|
|
||||||
ptr = (char_u *)skipwhite((char *)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); // NOLINT(runtime/printf)
|
|
||||||
ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, false);
|
|
||||||
tmp_ptr = ptr = (char_u *)skipwhite((char *)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] == '.'
|
|
||||||
|| 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;
|
|
||||||
}
|
|
||||||
STRLCPY(IObuff + len, ptr, IOSIZE - len);
|
|
||||||
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,
|
if (ins_compl_add_infercase(ptr, len, p_ic,
|
||||||
ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
|
ins_buf == curbuf ? NULL : (char_u *)ins_buf->b_sfname,
|
||||||
0, cont_s_ipos) != NOTDONE) {
|
0, cont_s_ipos) != NOTDONE) {
|
||||||
@@ -3060,6 +3118,31 @@ static int ins_compl_get_exp(pos_T *ini)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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, 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, 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, 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.
|
/// Delete the old text being completed.
|
||||||
void ins_compl_delete(void)
|
void ins_compl_delete(void)
|
||||||
{
|
{
|
||||||
@@ -3096,82 +3179,54 @@ void ins_compl_insert(bool in_compl_func)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill in the next completion in the current direction.
|
/// show the file name for the completion match (if any). Truncate the file
|
||||||
/// If "allow_get_expansion" is true, then we may call ins_compl_get_exp() to
|
/// name to avoid a wait for return.
|
||||||
/// get more completions. If it is false, then we just do nothing when there
|
static void ins_compl_show_filename(void)
|
||||||
/// 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
|
char *const lead = _("match in file");
|
||||||
/// through the ones found so far.
|
int space = sc_col - vim_strsize(lead) - 2;
|
||||||
/// @return the total number of matches, or -1 if still unknown -- webb.
|
if (space <= 0) {
|
||||||
///
|
return;
|
||||||
/// compl_curr_match is currently being used by ins_compl_get_exp(), so we use
|
}
|
||||||
/// compl_shown_match here.
|
|
||||||
///
|
// We need the tail that fits. With double-byte encoding going
|
||||||
/// Note that this function may be called recursively once only. First with
|
// back from the end is very slow, thus go from the start and keep
|
||||||
/// "allow_get_expansion" true, which calls ins_compl_get_exp(), which in turn
|
// the text that fits in "space" between "s" and "e".
|
||||||
/// calls this function with "allow_get_expansion" false.
|
char *s;
|
||||||
///
|
char *e;
|
||||||
/// @param count Repeat completion this many times; should be at least 1
|
for (s = e = (char *)compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e)) {
|
||||||
/// @param insert_match Insert the newly selected match
|
space -= ptr2cells(e);
|
||||||
/// @param in_compl_func Called from complete_check()
|
while (space < 0) {
|
||||||
static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match,
|
space += ptr2cells(s);
|
||||||
bool in_compl_func)
|
MB_PTR_ADV(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg_hist_off = true;
|
||||||
|
vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
|
||||||
|
(char_u *)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'.
|
||||||
|
///
|
||||||
|
/// @param allow_get_expansion If true, then ins_compl_get_exp() may be called to
|
||||||
|
/// get more completions.
|
||||||
|
/// If false, then do nothing when there are no more
|
||||||
|
/// completions in the given direction.
|
||||||
|
/// @param todo repeat completion this many times
|
||||||
|
/// @param advance If true, then completion will move to the first match.
|
||||||
|
/// Otherwise, the original text will be shown.
|
||||||
|
///
|
||||||
|
/// @return OK on success and -1 if the number of matches are unknown.
|
||||||
|
static int find_next_completion_match(bool allow_get_expansion, int todo, bool advance,
|
||||||
|
int *num_matches)
|
||||||
{
|
{
|
||||||
int num_matches = -1;
|
|
||||||
int todo = count;
|
|
||||||
compl_T *found_compl = NULL;
|
|
||||||
bool found_end = false;
|
bool found_end = false;
|
||||||
const bool started = compl_started;
|
compl_T *found_compl = NULL;
|
||||||
|
|
||||||
// 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, 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, 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, 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.
|
|
||||||
bool 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) {
|
while (--todo >= 0) {
|
||||||
if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL) {
|
if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL) {
|
||||||
compl_shown_match = compl_shown_match->cp_next;
|
compl_shown_match = compl_shown_match->cp_next;
|
||||||
@@ -3204,7 +3259,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find matches.
|
// Find matches.
|
||||||
num_matches = ins_compl_get_exp(&compl_startpos);
|
*num_matches = ins_compl_get_exp(&compl_startpos);
|
||||||
|
|
||||||
// handle any pending completions
|
// handle any pending completions
|
||||||
while (compl_pending != 0 && compl_direction == compl_shows_dir
|
while (compl_pending != 0 && compl_direction == compl_shows_dir
|
||||||
@@ -3242,6 +3297,69 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
///
|
||||||
|
/// @param count Repeat completion this many times; should be at least 1
|
||||||
|
/// @param insert_match Insert the newly selected match
|
||||||
|
/// @param in_compl_func Called from complete_check()
|
||||||
|
static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match,
|
||||||
|
bool in_compl_func)
|
||||||
|
{
|
||||||
|
int num_matches = -1;
|
||||||
|
int todo = count;
|
||||||
|
const bool 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.
|
||||||
|
bool 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.
|
// Insert the text of the new completion, or the compl_leader.
|
||||||
if (compl_no_insert && !started) {
|
if (compl_no_insert && !started) {
|
||||||
ins_bytes(compl_orig_text + get_compl_len());
|
ins_bytes(compl_orig_text + get_compl_len());
|
||||||
@@ -3277,31 +3395,8 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show the file name for the match (if any)
|
// 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) {
|
if (compl_shown_match->cp_fname != NULL) {
|
||||||
char *lead = _("match in file");
|
ins_compl_show_filename();
|
||||||
int space = sc_col - vim_strsize(lead) - 2;
|
|
||||||
char *s;
|
|
||||||
char *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 = (char *)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,
|
|
||||||
(char_u *)s > compl_shown_match->cp_fname ? "<" : "", s);
|
|
||||||
msg((char *)IObuff);
|
|
||||||
msg_hist_off = false;
|
|
||||||
redraw_cmdline = false; // don't overwrite!
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_matches;
|
return num_matches;
|
||||||
@@ -3711,49 +3806,16 @@ static int compl_get_info(char_u *line, int startcol, colnr_T curs_col, bool *li
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Do Insert mode completion.
|
/// Continue an interrupted completion mode search in "line".
|
||||||
/// Called when character "c" was typed, which has a meaning for completion.
|
///
|
||||||
/// Returns OK if completion was done, FAIL if something failed.
|
/// If this same ctrl_x_mode has been interrupted use the text from
|
||||||
int ins_complete(int c, bool enable_pum)
|
/// "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)
|
||||||
{
|
{
|
||||||
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;
|
|
||||||
const bool save_did_ai = did_ai;
|
|
||||||
int flags = CP_ORIGINAL_TEXT;
|
|
||||||
bool 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;
|
|
||||||
did_si = false;
|
|
||||||
can_si = false;
|
|
||||||
can_si_back = false;
|
|
||||||
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
|
// it is a continued search
|
||||||
compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
|
compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
|
||||||
if (ctrl_x_mode_normal()
|
if (ctrl_x_mode_normal()
|
||||||
@@ -3798,10 +3860,37 @@ int ins_complete(int c, bool enable_pum)
|
|||||||
} else {
|
} else {
|
||||||
compl_cont_status = 0;
|
compl_cont_status = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// start insert mode completion
|
||||||
|
static int ins_compl_start(void)
|
||||||
|
{
|
||||||
|
const bool save_did_ai = did_ai;
|
||||||
|
|
||||||
|
// First time we hit ^N or ^P (in a row, I mean)
|
||||||
|
|
||||||
|
did_ai = false;
|
||||||
|
did_si = false;
|
||||||
|
can_si = false;
|
||||||
|
can_si_back = false;
|
||||||
|
if (stop_arrow() == FAIL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char_u *line = ml_get(curwin->w_cursor.lnum);
|
||||||
|
colnr_T 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 {
|
} else {
|
||||||
compl_cont_status &= CONT_LOCAL;
|
compl_cont_status &= CONT_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int startcol = 0; // column where searched text starts
|
||||||
if (!(compl_cont_status & CONT_ADDING)) { // normal expansion
|
if (!(compl_cont_status & CONT_ADDING)) { // normal expansion
|
||||||
compl_cont_mode = ctrl_x_mode;
|
compl_cont_mode = ctrl_x_mode;
|
||||||
if (ctrl_x_mode_not_default()) {
|
if (ctrl_x_mode_not_default()) {
|
||||||
@@ -3815,6 +3904,7 @@ int ins_complete(int c, bool enable_pum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Work out completion pattern and original text -- webb
|
// Work out completion pattern and original text -- webb
|
||||||
|
bool line_invalid = false;
|
||||||
if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL) {
|
if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL) {
|
||||||
if (ctrl_x_mode_function() || ctrl_x_mode_omni()
|
if (ctrl_x_mode_function() || ctrl_x_mode_omni()
|
||||||
|| thesaurus_func_complete(ctrl_x_mode)) {
|
|| thesaurus_func_complete(ctrl_x_mode)) {
|
||||||
@@ -3860,6 +3950,7 @@ int ins_complete(int c, bool enable_pum)
|
|||||||
// Always add completion for the original text.
|
// Always add completion for the original text.
|
||||||
xfree(compl_orig_text);
|
xfree(compl_orig_text);
|
||||||
compl_orig_text = vim_strnsave(line + compl_col, (size_t)compl_length);
|
compl_orig_text = vim_strnsave(line + compl_col, (size_t)compl_length);
|
||||||
|
int flags = CP_ORIGINAL_TEXT;
|
||||||
if (p_ic) {
|
if (p_ic) {
|
||||||
flags |= CP_ICASE;
|
flags |= CP_ICASE;
|
||||||
}
|
}
|
||||||
@@ -3878,54 +3969,19 @@ int ins_complete(int c, bool enable_pum)
|
|||||||
showmode();
|
showmode();
|
||||||
edit_submode_extra = NULL;
|
edit_submode_extra = NULL;
|
||||||
ui_flush();
|
ui_flush();
|
||||||
} else if (insert_match && stop_arrow() == FAIL) {
|
|
||||||
return FAIL;
|
return OK;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
// we found no match if the list has only the "compl_orig_text"-entry
|
||||||
if (compl_first_match == compl_first_match->cp_next) {
|
if (compl_first_match == compl_first_match->cp_next) {
|
||||||
edit_submode_extra = (compl_cont_status & CONT_ADDING)
|
edit_submode_extra = (compl_cont_status & CONT_ADDING)
|
||||||
&& compl_length > 1
|
&& compl_length > 1
|
||||||
? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
|
? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
|
||||||
edit_submode_highl = HLF_E;
|
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_not_default()
|
|
||||||
&& !ctrl_x_mode_path_patterns()
|
|
||||||
&& !ctrl_x_mode_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 (edit_submode_extra == NULL) {
|
||||||
@@ -3985,6 +4041,72 @@ int ins_complete(int c, bool enable_pum)
|
|||||||
msg_clr_cmdline(); // necessary for "noshowmode"
|
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.
|
||||||
|
int ins_complete(int c, bool 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);
|
||||||
|
|
||||||
|
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_not_default()
|
||||||
|
&& !ctrl_x_mode_path_patterns()
|
||||||
|
&& !ctrl_x_mode_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.
|
// Show the popup menu, unless we got interrupted.
|
||||||
if (enable_pum && !compl_interrupted) {
|
if (enable_pum && !compl_interrupted) {
|
||||||
|
@@ -873,6 +873,25 @@ func Test_complete_stop()
|
|||||||
close!
|
close!
|
||||||
endfunc
|
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()
|
func Test_issue_7021()
|
||||||
CheckMSWindows
|
CheckMSWindows
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user