]> granicus.if.org Git - vim/commitdiff
patch 8.2.3912: the ins_complete() function is much too long v8.2.3912
authorBram Moolenaar <Bram@vim.org>
Mon, 27 Dec 2021 12:52:07 +0000 (12:52 +0000)
committerBram Moolenaar <Bram@vim.org>
Mon, 27 Dec 2021 12:52:07 +0000 (12:52 +0000)
Problem:    The ins_complete() function is much too long.
Solution:   Split it up into multiple functions. (Yegappan Lakshmanan,
            closes #9414)

src/insexpand.c
src/version.c

index bc490b96486d07a39f8729076f472913ffc0c6a9..b0319a26ed1e84bd811cdb11f1e315d7098caa03 100644 (file)
@@ -3831,6 +3831,364 @@ ins_compl_use_match(int c)
     return TRUE;
 }
 
+/*
+ * Get the pattern, column and length for normal completion (CTRL-N CTRL-P
+ * completion)
+ * Sets the global variables: compl_col, compl_length and compl_pattern.
+ * Uses the global variables: compl_cont_status and ctrl_x_mode
+ */
+    static int
+get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col)
+{
+    if ((compl_cont_status & CONT_SOL)
+           || ctrl_x_mode == CTRL_X_PATH_DEFINES)
+    {
+       if (!(compl_cont_status & CONT_ADDING))
+       {
+           while (--startcol >= 0 && vim_isIDc(line[startcol]))
+               ;
+           compl_col += ++startcol;
+           compl_length = curs_col - startcol;
+       }
+       if (p_ic)
+           compl_pattern = str_foldcase(line + compl_col,
+                   compl_length, NULL, 0);
+       else
+           compl_pattern = vim_strnsave(line + compl_col, compl_length);
+       if (compl_pattern == NULL)
+           return FAIL;
+    }
+    else if (compl_cont_status & CONT_ADDING)
+    {
+       char_u      *prefix = (char_u *)"\\<";
+
+       // we need up to 2 extra chars for the prefix
+       compl_pattern = alloc(quote_meta(NULL, line + compl_col,
+                   compl_length) + 2);
+       if (compl_pattern == NULL)
+           return FAIL;
+       if (!vim_iswordp(line + compl_col)
+               || (compl_col > 0
+                   && (vim_iswordp(mb_prevptr(line, line + compl_col)))))
+           prefix = (char_u *)"";
+       STRCPY((char *)compl_pattern, prefix);
+       (void)quote_meta(compl_pattern + STRLEN(prefix),
+               line + compl_col, compl_length);
+    }
+    else if (--startcol < 0
+           || !vim_iswordp(mb_prevptr(line, line + startcol + 1)))
+    {
+       // Match any word of at least two chars
+       compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
+       if (compl_pattern == NULL)
+           return FAIL;
+       compl_col += curs_col;
+       compl_length = 0;
+    }
+    else
+    {
+       // Search the point of change class of multibyte character
+       // or not a word single byte character backward.
+       if (has_mbyte)
+       {
+           int base_class;
+           int head_off;
+
+           startcol -= (*mb_head_off)(line, line + startcol);
+           base_class = mb_get_class(line + startcol);
+           while (--startcol >= 0)
+           {
+               head_off = (*mb_head_off)(line, line + startcol);
+               if (base_class != mb_get_class(line + startcol
+                           - head_off))
+                   break;
+               startcol -= head_off;
+           }
+       }
+       else
+           while (--startcol >= 0 && vim_iswordc(line[startcol]))
+               ;
+       compl_col += ++startcol;
+       compl_length = (int)curs_col - startcol;
+       if (compl_length == 1)
+       {
+           // Only match word with at least two chars -- webb
+           // there's no need to call quote_meta,
+           // alloc(7) is enough  -- Acevedo
+           compl_pattern = alloc(7);
+           if (compl_pattern == NULL)
+               return FAIL;
+           STRCPY((char *)compl_pattern, "\\<");
+           (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
+           STRCAT((char *)compl_pattern, "\\k");
+       }
+       else
+       {
+           compl_pattern = alloc(quote_meta(NULL, line + compl_col,
+                       compl_length) + 2);
+           if (compl_pattern == NULL)
+               return FAIL;
+           STRCPY((char *)compl_pattern, "\\<");
+           (void)quote_meta(compl_pattern + 2, line + compl_col,
+                   compl_length);
+       }
+    }
+
+    return OK;
+}
+
+/*
+ * Get the pattern, column and length for whole line completion or for the
+ * complete() function.
+ * Sets the global variables: compl_col, compl_length and compl_pattern.
+ */
+    static int
+get_wholeline_compl_info(char_u *line, colnr_T curs_col)
+{
+    compl_col = (colnr_T)getwhitecols(line);
+    compl_length = (int)curs_col - (int)compl_col;
+    if (compl_length < 0)      // cursor in indent: empty pattern
+       compl_length = 0;
+    if (p_ic)
+       compl_pattern = str_foldcase(line + compl_col, compl_length,
+               NULL, 0);
+    else
+       compl_pattern = vim_strnsave(line + compl_col, compl_length);
+    if (compl_pattern == NULL)
+       return FAIL;
+
+    return OK;
+}
+
+/*
+ * Get the pattern, column and length for filename completion.
+ * Sets the global variables: compl_col, compl_length and compl_pattern.
+ */
+    static int
+get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col)
+{
+    // Go back to just before the first filename character.
+    if (startcol > 0)
+    {
+       char_u  *p = line + startcol;
+
+       MB_PTR_BACK(line, p);
+       while (p > line && vim_isfilec(PTR2CHAR(p)))
+           MB_PTR_BACK(line, p);
+       if (p == line && vim_isfilec(PTR2CHAR(p)))
+           startcol = 0;
+       else
+           startcol = (int)(p - line) + 1;
+    }
+
+    compl_col += startcol;
+    compl_length = (int)curs_col - startcol;
+    compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES);
+    if (compl_pattern == NULL)
+       return FAIL;
+
+    return OK;
+}
+
+/*
+ * Get the pattern, column and length for command-line completion.
+ * Sets the global variables: compl_col, compl_length and compl_pattern.
+ */
+    static int
+get_cmdline_compl_info(char_u *line, colnr_T curs_col)
+{
+    compl_pattern = vim_strnsave(line, curs_col);
+    if (compl_pattern == NULL)
+       return FAIL;
+    set_cmd_context(&compl_xp, compl_pattern,
+           (int)STRLEN(compl_pattern), curs_col, FALSE);
+    if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
+           || compl_xp.xp_context == EXPAND_NOTHING)
+       // No completion possible, use an empty pattern to get a
+       // "pattern not found" message.
+       compl_col = curs_col;
+    else
+       compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
+    compl_length = curs_col - compl_col;
+
+    return OK;
+}
+
+/*
+ * Get the pattern, column and length for user defined completion ('omnifunc',
+ * 'completefunc' and 'thesaurusfunc')
+ * Sets the global variables: compl_col, compl_length and compl_pattern.
+ * Uses the global variable: spell_bad_len
+ */
+    static int
+get_userdefined_compl_info(colnr_T curs_col UNUSED)
+{
+    int                ret = FAIL;
+
+#ifdef FEAT_COMPL_FUNC
+    // Call user defined function 'completefunc' with "a:findstart"
+    // set to 1 to obtain the length of text to use for completion.
+    char_u     *line;
+    typval_T   args[3];
+    int                col;
+    char_u     *funcname;
+    pos_T      pos;
+    int                save_State = State;
+    callback_T *cb;
+
+    // Call 'completefunc' or 'omnifunc' or 'thesaurusfunc' and get pattern
+    // length as a string
+    funcname = get_complete_funcname(ctrl_x_mode);
+    if (*funcname == NUL)
+    {
+       semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
+               ? "completefunc" : "omnifunc");
+       return FAIL;
+    }
+
+    args[0].v_type = VAR_NUMBER;
+    args[0].vval.v_number = 1;
+    args[1].v_type = VAR_STRING;
+    args[1].vval.v_string = (char_u *)"";
+    args[2].v_type = VAR_UNKNOWN;
+    pos = curwin->w_cursor;
+    ++textwinlock;
+    cb = get_insert_callback(ctrl_x_mode);
+    col = call_callback_retnr(cb, 2, args);
+    --textwinlock;
+
+    State = save_State;
+    curwin->w_cursor = pos;    // restore the cursor position
+    validate_cursor();
+    if (!EQUAL_POS(curwin->w_cursor, pos))
+    {
+       emsg(_(e_compldel));
+       return FAIL;
+    }
+
+    // Return value -2 means the user complete function wants to
+    // cancel the complete without an error.
+    // Return value -3 does the same as -2 and leaves CTRL-X mode.
+    if (col == -2)
+       return FAIL;
+    if (col == -3)
+    {
+       ctrl_x_mode = CTRL_X_NORMAL;
+       edit_submode = NULL;
+       if (!shortmess(SHM_COMPLETIONMENU))
+           msg_clr_cmdline();
+       return FAIL;
+    }
+
+    // Reset extended parameters of completion, when start new
+    // completion.
+    compl_opt_refresh_always = FALSE;
+    compl_opt_suppress_empty = FALSE;
+
+    if (col < 0)
+       col = curs_col;
+    compl_col = col;
+    if (compl_col > curs_col)
+       compl_col = curs_col;
+
+    // Setup variables for completion.  Need to obtain "line" again,
+    // it may have become invalid.
+    line = ml_get(curwin->w_cursor.lnum);
+    compl_length = curs_col - compl_col;
+    compl_pattern = vim_strnsave(line + compl_col, compl_length);
+    if (compl_pattern == NULL)
+       return FAIL;
+
+    ret = OK;
+#endif
+
+    return ret;
+}
+
+/*
+ * Get the pattern, column and length for spell completion.
+ * Sets the global variables: compl_col, compl_length and compl_pattern.
+ * Uses the global variable: spell_bad_len
+ */
+    static int
+get_spell_compl_info(int startcol UNUSED, colnr_T curs_col UNUSED)
+{
+    int                ret = FAIL;
+#ifdef FEAT_SPELL
+    char_u     *line;
+
+    if (spell_bad_len > 0)
+       compl_col = curs_col - spell_bad_len;
+    else
+       compl_col = spell_word_start(startcol);
+    if (compl_col >= (colnr_T)startcol)
+    {
+       compl_length = 0;
+       compl_col = curs_col;
+    }
+    else
+    {
+       spell_expand_check_cap(compl_col);
+       compl_length = (int)curs_col - compl_col;
+    }
+    // Need to obtain "line" again, it may have become invalid.
+    line = ml_get(curwin->w_cursor.lnum);
+    compl_pattern = vim_strnsave(line + compl_col, compl_length);
+    if (compl_pattern == NULL)
+       return FAIL;
+
+    ret = OK;
+#endif
+
+    return ret;
+}
+
+/*
+ * Get the completion pattern, column and length.
+ */
+    static int
+compl_get_info(char_u *line, int startcol, colnr_T curs_col, int *line_invalid)
+{
+    if (ctrl_x_mode == CTRL_X_NORMAL
+           || (ctrl_x_mode & CTRL_X_WANT_IDENT
+               && !thesaurus_func_complete(ctrl_x_mode)))
+    {
+       return get_normal_compl_info(line, startcol, curs_col);
+    }
+    else if (ctrl_x_mode_line_or_eval())
+    {
+       return get_wholeline_compl_info(line, curs_col);
+    }
+    else if (ctrl_x_mode == CTRL_X_FILES)
+    {
+       return get_filename_compl_info(line, startcol, curs_col);
+    }
+    else if (ctrl_x_mode == CTRL_X_CMDLINE)
+    {
+       return get_cmdline_compl_info(line, curs_col);
+    }
+    else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
+           || thesaurus_func_complete(ctrl_x_mode))
+    {
+       if (get_userdefined_compl_info(curs_col) == FAIL)
+           return FAIL;
+       *line_invalid = TRUE;   // 'line' may have become invalid
+    }
+    else if (ctrl_x_mode == CTRL_X_SPELL)
+    {
+       if (get_spell_compl_info(startcol, curs_col) == FAIL)
+           return FAIL;
+       *line_invalid = TRUE;   // 'line' may have become invalid
+    }
+    else
+    {
+       internal_error("ins_complete()");
+       return FAIL;
+    }
+
+    return OK;
+}
+
 /*
  * Do Insert mode completion.
  * Called when character "c" was typed, which has a meaning for completion.
@@ -3846,10 +4204,9 @@ ins_complete(int c, int enable_pum)
     int                save_w_wrow;
     int                save_w_leftcol;
     int                insert_match;
-#ifdef FEAT_COMPL_FUNC
     int                save_did_ai = did_ai;
-#endif
     int                flags = CP_ORIGINAL_TEXT;
+    int                line_invalid = FALSE;
 
     compl_direction = ins_compl_key2dir(c);
     insert_match = ins_compl_use_match(c);
@@ -3947,273 +4304,24 @@ ins_complete(int c, int enable_pum)
        }
 
        // Work out completion pattern and original text -- webb
-       if (ctrl_x_mode == CTRL_X_NORMAL
-               || (ctrl_x_mode & CTRL_X_WANT_IDENT
-                   && !thesaurus_func_complete(ctrl_x_mode)))
+       if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL)
        {
-           if ((compl_cont_status & CONT_SOL)
-                   || ctrl_x_mode == CTRL_X_PATH_DEFINES)
-           {
-               if (!(compl_cont_status & CONT_ADDING))
-               {
-                   while (--startcol >= 0 && vim_isIDc(line[startcol]))
-                       ;
-                   compl_col += ++startcol;
-                   compl_length = curs_col - startcol;
-               }
-               if (p_ic)
-                   compl_pattern = str_foldcase(line + compl_col,
-                                                      compl_length, NULL, 0);
-               else
-                   compl_pattern = vim_strnsave(line + compl_col,
-                                                               compl_length);
-               if (compl_pattern == NULL)
-                   return FAIL;
-           }
-           else if (compl_cont_status & CONT_ADDING)
-           {
-               char_u      *prefix = (char_u *)"\\<";
-
-               // we need up to 2 extra chars for the prefix
-               compl_pattern = alloc(quote_meta(NULL, line + compl_col,
-                                                          compl_length) + 2);
-               if (compl_pattern == NULL)
-                   return FAIL;
-               if (!vim_iswordp(line + compl_col)
-                       || (compl_col > 0
-                        && (vim_iswordp(mb_prevptr(line, line + compl_col)))))
-                   prefix = (char_u *)"";
-               STRCPY((char *)compl_pattern, prefix);
-               (void)quote_meta(compl_pattern + STRLEN(prefix),
-                                             line + compl_col, compl_length);
-           }
-           else if (--startcol < 0
-                   || !vim_iswordp(mb_prevptr(line, line + startcol + 1)))
-           {
-               // Match any word of at least two chars
-               compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
-               if (compl_pattern == NULL)
-                   return FAIL;
-               compl_col += curs_col;
-               compl_length = 0;
-           }
-           else
-           {
-               // Search the point of change class of multibyte character
-               // or not a word single byte character backward.
-               if (has_mbyte)
-               {
-                   int base_class;
-                   int head_off;
-
-                   startcol -= (*mb_head_off)(line, line + startcol);
-                   base_class = mb_get_class(line + startcol);
-                   while (--startcol >= 0)
-                   {
-                       head_off = (*mb_head_off)(line, line + startcol);
-                       if (base_class != mb_get_class(line + startcol
-                                                                 - head_off))
-                           break;
-                       startcol -= head_off;
-                   }
-               }
-               else
-                   while (--startcol >= 0 && vim_iswordc(line[startcol]))
-                       ;
-               compl_col += ++startcol;
-               compl_length = (int)curs_col - startcol;
-               if (compl_length == 1)
-               {
-                   // Only match word with at least two chars -- webb
-                   // there's no need to call quote_meta,
-                   // alloc(7) is enough  -- Acevedo
-                   compl_pattern = alloc(7);
-                   if (compl_pattern == NULL)
-                       return FAIL;
-                   STRCPY((char *)compl_pattern, "\\<");
-                   (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
-                   STRCAT((char *)compl_pattern, "\\k");
-               }
-               else
-               {
-                   compl_pattern = alloc(quote_meta(NULL, line + compl_col,
-                                                          compl_length) + 2);
-                   if (compl_pattern == NULL)
-                       return FAIL;
-                   STRCPY((char *)compl_pattern, "\\<");
-                   (void)quote_meta(compl_pattern + 2, line + compl_col,
-                                                               compl_length);
-               }
-           }
-       }
-       else if (ctrl_x_mode_line_or_eval())
-       {
-           compl_col = (colnr_T)getwhitecols(line);
-           compl_length = (int)curs_col - (int)compl_col;
-           if (compl_length < 0)       // cursor in indent: empty pattern
-               compl_length = 0;
-           if (p_ic)
-               compl_pattern = str_foldcase(line + compl_col, compl_length,
-                                                                    NULL, 0);
-           else
-               compl_pattern = vim_strnsave(line + compl_col, compl_length);
-           if (compl_pattern == NULL)
-               return FAIL;
-       }
-       else if (ctrl_x_mode == CTRL_X_FILES)
-       {
-           // Go back to just before the first filename character.
-           if (startcol > 0)
-           {
-               char_u  *p = line + startcol;
-
-               MB_PTR_BACK(line, p);
-               while (p > line && vim_isfilec(PTR2CHAR(p)))
-                   MB_PTR_BACK(line, p);
-               if (p == line && vim_isfilec(PTR2CHAR(p)))
-                   startcol = 0;
-               else
-                   startcol = (int)(p - line) + 1;
-           }
-
-           compl_col += startcol;
-           compl_length = (int)curs_col - startcol;
-           compl_pattern = addstar(line + compl_col, compl_length,
-                                                               EXPAND_FILES);
-           if (compl_pattern == NULL)
-               return FAIL;
-       }
-       else if (ctrl_x_mode == CTRL_X_CMDLINE)
-       {
-           compl_pattern = vim_strnsave(line, curs_col);
-           if (compl_pattern == NULL)
-               return FAIL;
-           set_cmd_context(&compl_xp, compl_pattern,
-                                 (int)STRLEN(compl_pattern), curs_col, FALSE);
-           if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
-                   || compl_xp.xp_context == EXPAND_NOTHING)
-               // No completion possible, use an empty pattern to get a
-               // "pattern not found" message.
-               compl_col = curs_col;
-           else
-               compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
-           compl_length = curs_col - compl_col;
-       }
-       else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI
-               || thesaurus_func_complete(ctrl_x_mode))
-       {
-#ifdef FEAT_COMPL_FUNC
-           // Call user defined function 'completefunc' with "a:findstart"
-           // set to 1 to obtain the length of text to use for completion.
-           typval_T    args[3];
-           int         col;
-           char_u      *funcname;
-           pos_T       pos;
-           int         save_State = State;
-           callback_T  *cb;
-
-           // Call 'completefunc' or 'omnifunc' and get pattern length as a
-           // string
-           funcname = get_complete_funcname(ctrl_x_mode);
-           if (*funcname == NUL)
-           {
-               semsg(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
-                                            ? "completefunc" : "omnifunc");
+           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;
-           }
-
-           args[0].v_type = VAR_NUMBER;
-           args[0].vval.v_number = 1;
-           args[1].v_type = VAR_STRING;
-           args[1].vval.v_string = (char_u *)"";
-           args[2].v_type = VAR_UNKNOWN;
-           pos = curwin->w_cursor;
-           ++textwinlock;
-           cb = get_insert_callback(ctrl_x_mode);
-           col = call_callback_retnr(cb, 2, args);
-           --textwinlock;
-
-           State = save_State;
-           curwin->w_cursor = pos;     // restore the cursor position
-           validate_cursor();
-           if (!EQUAL_POS(curwin->w_cursor, pos))
-           {
-               emsg(_(e_compldel));
-               return FAIL;
-           }
-
-           // Return value -2 means the user complete function wants to
-           // cancel the complete without an error.
-           // Return value -3 does the same as -2 and leaves CTRL-X mode.
-           if (col == -2)
-               return FAIL;
-           if (col == -3)
-           {
-               ctrl_x_mode = CTRL_X_NORMAL;
-               edit_submode = NULL;
-               if (!shortmess(SHM_COMPLETIONMENU))
-                   msg_clr_cmdline();
-               return FAIL;
-           }
-
-           // Reset extended parameters of completion, when start new
-           // completion.
-           compl_opt_refresh_always = FALSE;
-           compl_opt_suppress_empty = FALSE;
-
-           if (col < 0)
-               col = curs_col;
-           compl_col = col;
-           if (compl_col > curs_col)
-               compl_col = curs_col;
-
-           // Setup variables for completion.  Need to obtain "line" again,
-           // it may have become invalid.
-           line = ml_get(curwin->w_cursor.lnum);
-           compl_length = curs_col - compl_col;
-           compl_pattern = vim_strnsave(line + compl_col, compl_length);
-           if (compl_pattern == NULL)
-#endif
-               return FAIL;
-       }
-       else if (ctrl_x_mode == CTRL_X_SPELL)
-       {
-#ifdef FEAT_SPELL
-           if (spell_bad_len > 0)
-               compl_col = curs_col - spell_bad_len;
-           else
-               compl_col = spell_word_start(startcol);
-           if (compl_col >= (colnr_T)startcol)
-           {
-               compl_length = 0;
-               compl_col = curs_col;
-           }
-           else
-           {
-               spell_expand_check_cap(compl_col);
-               compl_length = (int)curs_col - compl_col;
-           }
-           // Need to obtain "line" again, it may have become invalid.
-           line = ml_get(curwin->w_cursor.lnum);
-           compl_pattern = vim_strnsave(line + compl_col, compl_length);
-           if (compl_pattern == NULL)
-#endif
-               return FAIL;
-       }
-       else
-       {
-           internal_error("ins_complete()");
            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'
+               // Insert a new line, keep indentation but ignore 'comments'.
                char_u *old = curbuf->b_p_com;
 
                curbuf->b_p_com = (char_u *)"";
index 0d99bb857f2a15dfa175852267f32caed59d44d7..06a0a33700a199595d0ce31c7855b6d668e8ed1a 100644 (file)
@@ -749,6 +749,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3912,
 /**/
     3911,
 /**/