summaryrefslogtreecommitdiffstats
path: root/src/edit.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-03-30 13:53:47 +0100
committerBram Moolenaar <Bram@vim.org>2019-03-30 13:53:47 +0100
commit7591bb39d58ece38a5fef984a08ea9012616c1f9 (patch)
treee5e5b82ffd29f4f922ebfb5a97ea12a8b3624b7c /src/edit.c
parentde5b3800427328170574f1950ae75776e020f4e7 (diff)
patch 8.1.1076: file for Insert mode is much too bigv8.1.1076
Problem: File for Insert mode is much too big. Solution: Split off the code for Insert completion. (Yegappan Lakshmanan, closes #4044)
Diffstat (limited to 'src/edit.c')
-rw-r--r--src/edit.c4018
1 files changed, 52 insertions, 3966 deletions
diff --git a/src/edit.c b/src/edit.c
index dcead23f54..0b5d0e8086 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -13,210 +13,18 @@
#include "vim.h"
-#ifdef FEAT_INS_EXPAND
-/*
- * Definitions used for CTRL-X submode.
- * Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[] and
- * ctrl_x_mode_names[].
- */
-# define CTRL_X_WANT_IDENT 0x100
-
-# define CTRL_X_NORMAL 0 /* CTRL-N CTRL-P completion, default */
-# define CTRL_X_NOT_DEFINED_YET 1
-# define CTRL_X_SCROLL 2
-# define CTRL_X_WHOLE_LINE 3
-# define CTRL_X_FILES 4
-# define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
-# define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
-# define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
-# define CTRL_X_FINISHED 8
-# define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
-# define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
-# define CTRL_X_CMDLINE 11
-# define CTRL_X_FUNCTION 12
-# define CTRL_X_OMNI 13
-# define CTRL_X_SPELL 14
-# define CTRL_X_LOCAL_MSG 15 /* only used in "ctrl_x_msgs" */
-# define CTRL_X_EVAL 16 /* for builtin function complete() */
-
-# define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
-# define CTRL_X_MODE_LINE_OR_EVAL(m) ((m) == CTRL_X_WHOLE_LINE || (m) == CTRL_X_EVAL)
-
-// Message for CTRL-X mode, index is ctrl_x_mode.
-static char *ctrl_x_msgs[] =
-{
- N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
- N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
- NULL, // CTRL_X_SCROLL: depends on state
- N_(" Whole line completion (^L^N^P)"),
- N_(" File name completion (^F^N^P)"),
- N_(" Tag completion (^]^N^P)"),
- N_(" Path pattern completion (^N^P)"),
- N_(" Definition completion (^D^N^P)"),
- NULL, // CTRL_X_FINISHED
- N_(" Dictionary completion (^K^N^P)"),
- N_(" Thesaurus completion (^T^N^P)"),
- N_(" Command-line completion (^V^N^P)"),
- N_(" User defined completion (^U^N^P)"),
- N_(" Omni completion (^O^N^P)"),
- N_(" Spelling suggestion (s^N^P)"),
- N_(" Keyword Local completion (^N^P)"),
- NULL, // CTRL_X_EVAL doesn't use msg.
-};
-
-static char *ctrl_x_mode_names[] = {
- "keyword",
- "ctrl_x",
- "unknown", // CTRL_X_SCROLL
- "whole_line",
- "files",
- "tags",
- "path_patterns",
- "path_defines",
- "unknown", // CTRL_X_FINISHED
- "dictionary",
- "thesaurus",
- "cmdline",
- "function",
- "omni",
- "spell",
- NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
- "eval"
- };
-
-
-static char e_hitend[] = N_("Hit end of paragraph");
-# ifdef FEAT_COMPL_FUNC
-static char e_complwin[] = N_("E839: Completion function changed window");
-static char e_compldel[] = N_("E840: Completion function deleted text");
-# endif
-
-/*
- * Structure used to store one match for insert completion.
- */
-typedef struct compl_S compl_T;
-struct compl_S
-{
- compl_T *cp_next;
- compl_T *cp_prev;
- char_u *cp_str; /* matched text */
- char cp_icase; /* TRUE or FALSE: ignore case */
- char_u *(cp_text[CPT_COUNT]); /* text for the menu */
- char_u *cp_fname; /* file containing the match, allocated when
- * cp_flags has FREE_FNAME */
- int cp_flags; /* ORIGINAL_TEXT, CONT_S_IPOS or FREE_FNAME */
- int cp_number; /* sequence number */
-};
-
-# define ORIGINAL_TEXT (1) /* the original text when the expansion begun */
-# define FREE_FNAME (2)
-
-/*
- * All the current matches are stored in a list.
- * "compl_first_match" points to the start of the list.
- * "compl_curr_match" points to the currently selected entry.
- * "compl_shown_match" is different from compl_curr_match during
- * ins_compl_get_exp().
- */
-static compl_T *compl_first_match = NULL;
-static compl_T *compl_curr_match = NULL;
-static compl_T *compl_shown_match = NULL;
-static compl_T *compl_old_match = NULL;
-
-/* After using a cursor key <Enter> selects a match in the popup menu,
- * otherwise it inserts a line break. */
-static int compl_enter_selects = FALSE;
-
-/* When "compl_leader" is not NULL only matches that start with this string
- * are used. */
-static char_u *compl_leader = NULL;
-
-static int compl_get_longest = FALSE; /* put longest common string
- in compl_leader */
-
-static int compl_no_insert = FALSE; /* FALSE: select & insert
- TRUE: noinsert */
-static int compl_no_select = FALSE; /* FALSE: select & insert
- TRUE: noselect */
-
-static int compl_used_match; /* Selected one of the matches. When
- FALSE the match was edited or using
- the longest common string. */
-
-static int compl_was_interrupted = FALSE; /* didn't finish finding
- completions. */
-
-static int compl_restarting = FALSE; /* don't insert match */
-
-/* When the first completion is done "compl_started" is set. When it's
- * FALSE the word to be completed must be located. */
-static int compl_started = FALSE;
-
-/* Which Ctrl-X mode are we in? */
-static int ctrl_x_mode = CTRL_X_NORMAL;
+#define BACKSPACE_CHAR 1
+#define BACKSPACE_WORD 2
+#define BACKSPACE_WORD_NOT_SPACE 3
+#define BACKSPACE_LINE 4
+#ifdef FEAT_INS_EXPAND
/* Set when doing something for completion that may call edit() recursively,
* which is not allowed. */
-static int compl_busy = FALSE;
-
-static int compl_matches = 0;
-static char_u *compl_pattern = NULL;
-static int compl_direction = FORWARD;
-static int compl_shows_dir = FORWARD;
-static int compl_pending = 0; /* > 1 for postponed CTRL-N */
-static pos_T compl_startpos;
-static colnr_T compl_col = 0; /* column where the text starts
- * that is being completed */
-static char_u *compl_orig_text = NULL; /* text as it was before
- * completion started */
-static int compl_cont_mode = 0;
-static expand_T compl_xp;
-
-static int compl_opt_refresh_always = FALSE;
-static int compl_opt_suppress_empty = FALSE;
-
-static void ins_ctrl_x(void);
-static int has_compl_option(int dict_opt);
-static int ins_compl_accept_char(int c);
-static int ins_compl_add(char_u *str, int len, int icase, char_u *fname, char_u **cptext, int cdir, int flags, int adup);
-static void ins_compl_longest_match(compl_T *match);
-static void ins_compl_del_pum(void);
-static int pum_wanted(void);
-static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir);
-static char_u *find_line_end(char_u *ptr);
-static void ins_compl_free(void);
-static void ins_compl_clear(void);
-static char_u *ins_compl_mode(void);
-static int ins_compl_bs(void);
-static int ins_compl_need_restart(void);
-static void ins_compl_new_leader(void);
-static void ins_compl_addleader(int c);
-static int ins_compl_len(void);
-static void ins_compl_restart(void);
-static void ins_compl_set_original_text(char_u *str);
-static void ins_compl_addfrommatch(void);
-static int ins_compl_prep(int c);
-static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg);
-# if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
-static void ins_compl_add_list(list_T *list);
-static void ins_compl_add_dict(dict_T *dict);
-# endif
-static void ins_compl_delete(void);
-static void ins_compl_insert(int in_compl_func);
-static int ins_compl_key2dir(int c);
-static int ins_compl_pum_key(int c);
-static int ins_compl_key2count(int c);
-static int ins_complete(int c, int enable_pum);
-static void show_pum(int prev_w_wrow, int prev_w_leftcol);
-static unsigned quote_meta(char_u *dest, char_u *str, int len);
+static int compl_busy = FALSE;
#endif /* FEAT_INS_EXPAND */
-#define BACKSPACE_CHAR 1
-#define BACKSPACE_WORD 2
-#define BACKSPACE_WORD_NOT_SPACE 3
-#define BACKSPACE_LINE 4
-static void ins_redraw(int ready);
static void ins_ctrl_v(void);
#ifdef FEAT_JOB_CHANNEL
static void init_prompt(int cmdchar_todo);
@@ -226,12 +34,9 @@ static void insert_special(int, int, int);
static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c);
static void check_auto_format(int);
static void redo_literal(int c);
-static void start_arrow(pos_T *end_insert_pos);
static void start_arrow_common(pos_T *end_insert_pos, int change);
#ifdef FEAT_SPELL
static void check_spell_redraw(void);
-static void spell_back_to_badword(void);
-static int spell_bad_len = 0; /* length of located bad word */
#endif
static void stop_insert(pos_T *end_insert_pos, int esc, int nomove);
static int echeck_abbr(int);
@@ -274,7 +79,6 @@ static void ins_pagedown(void);
static void ins_drop(void);
#endif
static int ins_tab(void);
-static int ins_eol(int c);
#ifdef FEAT_DIGRAPHS
static int ins_digraph(void);
#endif
@@ -285,7 +89,6 @@ static void ins_try_si(int c);
#if defined(FEAT_EVAL)
static char_u *do_insert_char_pre(int c);
#endif
-static int ins_apply_autocmds(event_T event);
static colnr_T Insstart_textlen; /* length of line when insert started */
static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
@@ -393,7 +196,7 @@ edit(
#ifdef FEAT_INS_EXPAND
/* Don't allow recursive insert mode when busy with completion. */
- if (compl_started || compl_busy || pum_visible())
+ if (ins_compl_active() || compl_busy || pum_visible())
{
emsg(_(e_secure));
return FALSE;
@@ -834,28 +637,26 @@ edit(
* and the cursor is still in the completed word. Only when there is
* a match, skip this when no matches were found.
*/
- if (compl_started
+ if (ins_compl_active()
&& pum_wanted()
- && curwin->w_cursor.col >= compl_col
- && (compl_shown_match == NULL
- || compl_shown_match != compl_shown_match->cp_next))
+ && curwin->w_cursor.col >= ins_compl_col()
+ && ins_compl_has_shown_match())
{
/* BS: Delete one character from "compl_leader". */
if ((c == K_BS || c == Ctrl_H)
- && curwin->w_cursor.col > compl_col
+ && curwin->w_cursor.col > ins_compl_col()
&& (c = ins_compl_bs()) == NUL)
continue;
/* When no match was selected or it was edited. */
- if (!compl_used_match)
+ if (!ins_compl_used_match())
{
/* CTRL-L: Add one character from the current match to
* "compl_leader". Except when at the original match and
* there is nothing to add, CTRL-L works like CTRL-P then. */
if (c == Ctrl_L
- && (!CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
- || (int)STRLEN(compl_shown_match->cp_str)
- > curwin->w_cursor.col - compl_col))
+ && (!ctrl_x_mode_line_or_eval()
+ || ins_compl_long_shown_match()))
{
ins_compl_addfrommatch();
continue;
@@ -883,8 +684,9 @@ edit(
}
/* Pressing CTRL-Y selects the current match. When
- * compl_enter_selects is set the Enter key does the same. */
- if ((c == Ctrl_Y || (compl_enter_selects
+ * ins_compl_enter_selects() is set the Enter key does the
+ * same. */
+ if ((c == Ctrl_Y || (ins_compl_enter_selects()
&& (c == CAR || c == K_KENTER || c == NL)))
&& stop_arrow() == OK)
{
@@ -896,7 +698,7 @@ edit(
/* Prepare for or stop CTRL-X mode. This doesn't do completion, but
* it does fix up the text when finishing completion. */
- compl_get_longest = FALSE;
+ ins_compl_init_get_longest();
if (ins_compl_prep(c))
continue;
#endif
@@ -939,7 +741,7 @@ edit(
#endif
#ifdef FEAT_INS_EXPAND
- if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE)
+ if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode_cmdline())
goto docomplete;
#endif
if (c == Ctrl_V || c == Ctrl_Q)
@@ -952,7 +754,7 @@ edit(
#ifdef FEAT_CINDENT
if (cindent_on()
# ifdef FEAT_INS_EXPAND
- && ctrl_x_mode == 0
+ && ctrl_x_mode_none()
# endif
)
{
@@ -1073,7 +875,7 @@ doESCkey:
case Ctrl_O: /* execute one command */
#ifdef FEAT_COMPL_FUNC
- if (ctrl_x_mode == CTRL_X_OMNI)
+ if (ctrl_x_mode_omni())
goto docomplete;
#endif
if (echeck_abbr(Ctrl_O + ABBR_OFF))
@@ -1149,14 +951,14 @@ doESCkey:
case Ctrl_D: /* Make indent one shiftwidth smaller. */
#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
- if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
+ if (ctrl_x_mode_path_defines())
goto docomplete;
#endif
/* FALLTHROUGH */
case Ctrl_T: /* Make indent one shiftwidth greater. */
# ifdef FEAT_INS_EXPAND
- if (c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS)
+ if (c == Ctrl_T && ctrl_x_mode_thesaurus())
{
if (has_compl_option(FALSE))
goto docomplete;
@@ -1200,7 +1002,7 @@ doESCkey:
case Ctrl_U: /* delete all inserted text in current line */
# ifdef FEAT_COMPL_FUNC
/* CTRL-X CTRL-U completes with 'completefunc'. */
- if (ctrl_x_mode == CTRL_X_FUNCTION)
+ if (ctrl_x_mode_function())
goto docomplete;
# endif
did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
@@ -1382,7 +1184,7 @@ doESCkey:
case TAB: /* TAB or Complete patterns along path */
#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
- if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
+ if (ctrl_x_mode_path_patterns())
goto docomplete;
#endif
inserted_space = FALSE;
@@ -1436,7 +1238,7 @@ doESCkey:
#if defined(FEAT_DIGRAPHS) || defined(FEAT_INS_EXPAND)
case Ctrl_K: /* digraph or keyword completion */
# ifdef FEAT_INS_EXPAND
- if (ctrl_x_mode == CTRL_X_DICTIONARY)
+ if (ctrl_x_mode_dictionary())
{
if (has_compl_option(TRUE))
goto docomplete;
@@ -1457,25 +1259,25 @@ doESCkey:
break;
case Ctrl_RSB: /* Tag name completion after ^X */
- if (ctrl_x_mode != CTRL_X_TAGS)
+ if (!ctrl_x_mode_tags())
goto normalchar;
goto docomplete;
case Ctrl_F: /* File name completion after ^X */
- if (ctrl_x_mode != CTRL_X_FILES)
+ if (!ctrl_x_mode_files())
goto normalchar;
goto docomplete;
case 's': /* Spelling completion after ^X */
case Ctrl_S:
- if (ctrl_x_mode != CTRL_X_SPELL)
+ if (!ctrl_x_mode_spell())
goto normalchar;
goto docomplete;
#endif
case Ctrl_L: /* Whole line completion after ^X */
#ifdef FEAT_INS_EXPAND
- if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
+ if (!ctrl_x_mode_whole_line())
#endif
{
/* CTRL-L with 'insertmode' set: Leave Insert mode */
@@ -1495,8 +1297,7 @@ doESCkey:
/* if 'complete' is empty then plain ^P is no longer special,
* but it is under other ^X modes */
if (*curbuf->b_p_cpt == NUL
- && (ctrl_x_mode == CTRL_X_NORMAL
- || ctrl_x_mode == CTRL_X_WHOLE_LINE)
+ && (ctrl_x_mode_normal() || ctrl_x_mode_whole_line())
&& !(compl_cont_status & CONT_LOCAL))
goto normalchar;
@@ -1608,7 +1409,7 @@ normalchar:
if (c != K_CURSORHOLD
#ifdef FEAT_COMPL_FUNC
/* but not in CTRL-X mode, a script can't restore the state */
- && ctrl_x_mode == CTRL_X_NORMAL
+ && ctrl_x_mode_normal()
#endif
)
did_cursorhold = FALSE;
@@ -1620,7 +1421,7 @@ normalchar:
#ifdef FEAT_CINDENT
if (can_cindent && cindent_on()
# ifdef FEAT_INS_EXPAND
- && ctrl_x_mode == CTRL_X_NORMAL
+ && ctrl_x_mode_normal()
# endif
)
{
@@ -1641,6 +1442,12 @@ force_cindent:
/* NOTREACHED */
}
+ int
+ins_need_undo_get(void)
+{
+ return ins_need_undo;
+}
+
/*
* Redraw for Insert mode.
* This is postponed until getting the next character to make '$' in the 'cpo'
@@ -1648,7 +1455,7 @@ force_cindent:
* Only redraw when there are no characters available. This speeds up
* inserting sequences of characters (e.g., for CTRL-R).
*/
- static void
+ void
ins_redraw(
int ready UNUSED) /* not busy with something */
{
@@ -2313,3719 +2120,6 @@ del_char_after_col(int limit_col UNUSED)
return TRUE;
}
-#if defined(FEAT_INS_EXPAND) || defined(PROTO)
-/*
- * CTRL-X pressed in Insert mode.
- */
- static void
-ins_ctrl_x(void)
-{
- /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
- * CTRL-V works like CTRL-N */
- if (ctrl_x_mode != CTRL_X_CMDLINE)
- {
- /* if the next ^X<> won't ADD nothing, then reset
- * compl_cont_status */
- if (compl_cont_status & CONT_N_ADDS)
- compl_cont_status |= CONT_INTRPT;
- else
- compl_cont_status = 0;
- /* We're not sure which CTRL-X mode it will be yet */
- ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
- edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
- edit_submode_pre = NULL;
- showmode();
- }
-}
-
-/*
- * Whether other than default completion has been selected.
- */
- int
-ctrl_x_mode_not_default(void)
-{
- return ctrl_x_mode != CTRL_X_NORMAL;
-}
-
-/*
- * Whether CTRL-X was typed without a following character.
- */
- int
-ctrl_x_mode_not_defined_yet(void)
-{
- return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
-}
-
-/*
- * Return TRUE if the 'dict' or 'tsr' option can be used.
- */
- static int
-has_compl_option(int dict_opt)
-{
- if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
-# ifdef FEAT_SPELL
- && !curwin->w_p_spell
-# endif
- )
- : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL))
- {
- ctrl_x_mode = CTRL_X_NORMAL;
- edit_submode = NULL;
- msg_attr(dict_opt ? _("'dictionary' option is empty")
- : _("'thesaurus' option is empty"),
- HL_ATTR(HLF_E));
- if (emsg_silent == 0)
- {
- vim_beep(BO_COMPL);
- setcursor();
- out_flush();
-#ifdef FEAT_EVAL
- if (!get_vim_var_nr(VV_TESTING))
-#endif
- ui_delay(2000L, FALSE);
- }
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * Is the character 'c' a valid key to go to or keep us in CTRL-X mode?
- * This depends on the current mode.
- */
- int
-vim_is_ctrl_x_key(int c)
-{
- // Always allow ^R - let its results then be checked
- if (c == Ctrl_R)
- return TRUE;
-
- /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
- if (ins_compl_pum_key(c))
- return TRUE;
-
- switch (ctrl_x_mode)
- {
- case 0: /* Not in any CTRL-X mode */
- return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
- case CTRL_X_NOT_DEFINED_YET:
- return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
- || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
- || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
- || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
- || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
- || c == Ctrl_S || c == Ctrl_K || c == 's');
- case CTRL_X_SCROLL:
- return (c == Ctrl_Y || c == Ctrl_E);
- case CTRL_X_WHOLE_LINE:
- return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_FILES:
- return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_DICTIONARY:
- return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_THESAURUS:
- return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_TAGS:
- return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
-#ifdef FEAT_FIND_ID
- case CTRL_X_PATH_PATTERNS:
- return (c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_PATH_DEFINES:
- return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
-#endif
- case CTRL_X_CMDLINE:
- return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
- || c == Ctrl_X);
-#ifdef FEAT_COMPL_FUNC
- case CTRL_X_FUNCTION:
- return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_OMNI:
- return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
-#endif
- case CTRL_X_SPELL:
- return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
- case CTRL_X_EVAL:
- return (c == Ctrl_P || c == Ctrl_N);
- }
- internal_error("vim_is_ctrl_x_key()");
- return FALSE;
-}
-
-/*
- * Return TRUE when character "c" is part of the item currently being
- * completed. Used to decide whether to abandon complete mode when the menu
- * is visible.
- */
- static int
-ins_compl_accept_char(int c)
-{
- if (ctrl_x_mode & CTRL_X_WANT_IDENT)
- /* When expanding an identifier only accept identifier chars. */
- return vim_isIDc(c);
-
- switch (ctrl_x_mode)
- {
- case CTRL_X_FILES:
- /* When expanding file name only accept file name chars. But not
- * path separators, so that "proto/<Tab>" expands files in
- * "proto", not "proto/" as a whole */
- return vim_isfilec(c) && !vim_ispathsep(c);
-
- case CTRL_X_CMDLINE:
- case CTRL_X_OMNI:
- /* Command line and Omni completion can work with just about any
- * printable character, but do stop at white space. */
- return vim_isprintc(c) && !VIM_ISWHITE(c);
-
- case CTRL_X_WHOLE_LINE:
- /* For while line completion a space can be part of the line. */
- return vim_isprintc(c);
- }
- return vim_iswordc(c);
-}
-
-/*
- * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
- * case of the originally typed text is used, and the case of the completed
- * text is inferred, ie this tries to work out what case you probably wanted
- * the rest of the word to be in -- webb
- */
- int
-ins_compl_add_infercase(
- char_u *str,
- int len,
- int icase,
- char_u *fname,
- int dir,
- int flags)
-{
- char_u *p;
- int i, c;
- int actual_len; /* Take multi-byte characters */
- int actual_compl_length; /* into account. */
- int min_len;
- int *wca; /* Wide character array. */
- int has_lower = FALSE;
- int was_letter = FALSE;
-
- if (p_ic && curbuf->b_p_inf && len > 0)
- {
- /* Infer case of completed part. */
-
- /* Find actual length of completion. */
- if (has_mbyte)
- {
- p = str;
- actual_len = 0;
- while (*p != NUL)
- {
- MB_PTR_ADV(p);
- ++actual_len;
- }
- }
- else
- actual_len = len;
-
- /* Find actual length of original text. */
- if (has_mbyte)
- {
- p = compl_orig_text;
- actual_compl_length = 0;
- while (*p != NUL)
- {
- MB_PTR_ADV(p);
- ++actual_compl_length;
- }
- }
- else
- actual_compl_length = compl_length;
-
- /* "actual_len" may be smaller than "actual_compl_length" when using
- * thesaurus, only use the minimum when comparing. */
- min_len = actual_len < actual_compl_length
- ? actual_len : actual_compl_length;
-
- /* Allocate wide character array for the completion and fill it. */
- wca = (int *)alloc((unsigned)(actual_len * sizeof(int)));
- if (wca != NULL)
- {
- p = str;
- for (i = 0; i < actual_len; ++i)
- if (has_mbyte)
- wca[i] = mb_ptr2char_adv(&p);
- else
- wca[i] = *(p++);
-
- /* Rule 1: Were any chars converted to lower? */
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i)
- {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(p++);
- if (MB_ISLOWER(c))
- {
- has_lower = TRUE;
- if (MB_ISUPPER(wca[i]))
- {
- /* Rule 1 is satisfied. */
- for (i = actual_compl_length; i < actual_len; ++i)
- wca[i] = MB_TOLOWER(wca[i]);
- break;
- }
- }
- }
-
- /*
- * Rule 2: No lower case, 2nd consecutive letter converted to
- * upper case.
- */
- if (!has_lower)
- {
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i)
- {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(p++);
- if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i]))
- {
- /* Rule 2 is satisfied. */
- for (i = actual_compl_length; i < actual_len; ++i)
- wca[i] = MB_TOUPPER(wca[i]);
- break;
- }
- was_letter = MB_ISLOWER(c) || MB_ISUPPER(c);
- }
- }
-
- /* Copy the original case of the part we typed. */
- p = compl_orig_text;
- for (i = 0; i < min_len; ++i)
- {
- if (has_mbyte)
- c = mb_ptr2char_adv(&p);
- else
- c = *(p++);
- if (MB_ISLOWER(c))
- wca[i] = MB_TOLOWER(wca[i]);
- else if (MB_ISUPPER(c))
- wca[i] = MB_TOUPPER(wca[i]);
- }
-
- /*
- * Generate encoding specific output from wide character array.
- * Multi-byte characters can occupy up to five bytes more than
- * ASCII characters, and we also need one byte for NUL, so stay
- * six bytes away from the edge of IObuff.
- */
- p = IObuff;
- i = 0;
- while (i < actual_len && (p - IObuff + 6) < IOSIZE)
- if (has_mbyte)
- p += (*mb_char2bytes)(wca[i++], p);
- else
- *(p++) = wca[i++];
- *p = NUL;
-
- vim_free(wca);
- }
-
- return ins_compl_add(IObuff, len, icase, fname, NULL, dir,
- flags, FALSE);
- }
- return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE);
-}
-
-/*
- * Add a match to the list of matches.
- * If the given string is already in the list of completions, then return
- * NOTDONE, otherwise add it to the list and return OK. If there is an error,
- * maybe because alloc() returns NULL, then FAIL is returned.
- */
- static int
-ins_compl_add(
- char_u *str,
- int len,
- int icase,
- char_u *fname,
- char_u **cptext, /* extra text for popup menu or NULL */
- int cdir,
- int flags,
- int adup) /* accept duplicate match */
-{
- compl_T *match;
- int dir = (cdir == 0 ? compl_direction : cdir);
-
- ui_breakcheck();
- if (got_int)
- return FAIL;
- if (len < 0)
- len = (int)STRLEN(str);
-
- /*
- * If the same match is already present, don't add it.
- */
- if (compl_first_match != NULL && !adup)
- {
- match = compl_first_match;
- do
- {
- if ( !(match->cp_flags & ORIGINAL_TEXT)
- && STRNCMP(match->cp_str, str, len) == 0
- && match->cp_str[len] == NUL)
- return NOTDONE;
- match = match->cp_next;
- } while (match != NULL && match != compl_first_match);
- }
-
- /* Remove any popup menu before changing the list of matches. */
- ins_compl_del_pum();
-
- /*
- * Allocate a new match structure.
- * Copy the values to the new match structure.
- */
- match = (compl_T *)alloc_clear((unsigned)sizeof(compl_T));
- if (match == NULL)
- return FAIL;
- match->cp_number = -1;
- if (flags & ORIGINAL_TEXT)
- match->cp_number = 0;
- if ((match->cp_str = vim_strnsave(str, len)) == NULL)
- {
- vim_free(match);
- return FAIL;
- }
- match->cp_icase = icase;
-
- /* match-fname is:
- * - compl_curr_match->cp_fname if it is a string equal to fname.
- * - a copy of fname, FREE_FNAME is set to free later THE allocated mem.
- * - NULL otherwise. --Acevedo */
- if (fname != NULL
- && compl_curr_match != NULL
- && compl_curr_match->cp_fname != NULL
- && STRCMP(fname, compl_curr_match->cp_fname) == 0)
- match->cp_fname = compl_curr_match->cp_fname;
- else if (fname != NULL)
- {
- match->cp_fname = vim_strsave(fname);
- flags |= FREE_FNAME;
- }
- else
- match->cp_fname = NULL;
- match->cp_flags = flags;
-
- if (cptext != NULL)
- {
- int i;
-
- for (i = 0; i < CPT_COUNT; ++i)
- if (cptext[i] != NULL && *cptext[i] != NUL)
- match->cp_text[i] = vim_strsave(cptext[i]);
- }
-
- /*
- * Link the new match structure in the list of matches.
- */
- if (compl_first_match == NULL)
- match->cp_next = match->cp_prev = NULL;
- else if (dir == FORWARD)
- {
- match->cp_next = compl_curr_match->cp_next;
- match->cp_prev = compl_curr_match;
- }
- else /* BACKWARD */
- {
- match->cp_next = compl_curr_match;
- match->cp_prev = compl_curr_match->cp_prev;
- }
- if (match->cp_next)
- match->cp_next->cp_prev = match;
- if (match->cp_prev)
- match->cp_prev->cp_next = match;
- else /* if there's nothing before, it is the first match */
- compl_first_match = match;
- compl_curr_match = match;
-
- /*
- * Find the longest common string if still doing that.
- */
- if (compl_get_longest && (flags & ORIGINAL_TEXT) == 0)
- ins_compl_longest_match(match);
-
- return OK;
-}
-
-/*
- * Return TRUE if "str[len]" matches with match->cp_str, considering
- * match->cp_icase.
- */
- static int
-ins_compl_equal(compl_T *match, char_u *str, int len)
-{
- if (match->cp_icase)
- return STRNICMP(match->cp_str, str, (size_t)len) == 0;
- return STRNCMP(match->cp_str, str, (size_t)len) == 0;
-}
-
-/*
- * Reduce the longest common string for match "match".
- */
- static void
-ins_compl_longest_match(compl_T *match)
-{
- char_u *p, *s;
- int c1, c2;
- int had_match;
-
- if (compl_leader == NULL)
- {
- /* First match, use it as a whole. */
- compl_leader = vim_strsave(match->cp_str);
- if (compl_leader != NULL)
- {
- had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + ins_compl_len());
- ins_redraw(FALSE);
-
- /* When the match isn't there (to avoid matching itself) remove it
- * again after redrawing. */
- if (!had_match)
- ins_compl_delete();
- compl_used_match = FALSE;
- }
- }
- else
- {
- /* Reduce the text if this match differs from compl_leader. */
- p = compl_leader;
- s = match->cp_str;
- while (*p != NUL)
- {
- if (has_mbyte)
- {
- c1 = mb_ptr2char(p);
- c2 = mb_ptr2char(s);
- }
- else
- {
- c1 = *p;
- c2 = *s;
- }
- if (match->cp_icase ? (MB_TOLOWER(c1) != MB_TOLOWER(c2))
- : (c1 != c2))
- break;
- if (has_mbyte)
- {
- MB_PTR_ADV(p);
- MB_PTR_ADV(s);
- }
- else
- {
- ++p;
- ++s;
- }
- }
-
- if (*p != NUL)
- {
- /* Leader was shortened, need to change the inserted text. */
- *p = NUL;
- had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + ins_compl_len());
- ins_redraw(FALSE);
-
- /* When the match isn't there (to avoid matching itself) remove it
- * again after redrawing. */
- if (!had_match)
- ins_compl_delete();
- }
-
- compl_used_match = FALSE;
- }
-}
-
-/*
- * Add an array of matches to the list of matches.
- * Frees matches[].
- */
- static void
-ins_compl_add_matches(
- int num_matches,
- char_u **matches,
- int icase)
-{
- int i;
- int add_r = OK;
- int dir = compl_direction;
-
- for (i = 0; i < num_matches && add_r != FAIL; i++)
- if ((add_r = ins_compl_add(matches[i], -1, icase,
- NULL, NULL, dir, 0, FALSE)) == OK)
- /* if dir was BACKWARD then honor it just once */
- dir = FORWARD;
- FreeWild(num_matches, matches);
-}
-
-/* Make the completion list cyclic.
- * Return the number of matches (excluding the original).
- */
- static int
-ins_compl_make_cyclic(void)
-{
- compl_T *match;
- int count = 0;
-
- if (compl_first_match != NULL)
- {
- /*
- * Find the end of the list.
- */
- match = compl_first_match;
- /* there's always an entry for the compl_orig_text, it doesn't count. */
- while (match->cp_next != NULL && match->cp_next != compl_first_match)
- {
- match = match->cp_next;
- ++count;
- }
- match->cp_next = compl_first_match;
- compl_first_match->cp_prev = match;
- }
- return count;
-}
-
-/*
- * Set variables that store noselect and noinsert behavior from the
- * 'completeopt' value.
- */
- void
-completeopt_was_set(void)
-{
- compl_no_insert = FALSE;
- compl_no_select = FALSE;
- if (strstr((char *)p_cot, "noselect") != NULL)
- compl_no_select = TRUE;
- if (strstr((char *)p_cot, "noinsert") != NULL)
- compl_no_insert = TRUE;
-}
-
-/*
- * Start completion for the complete() function.
- * "startcol" is where the matched text starts (1 is first column).
- * "list" is the list of matches.
- */
- void
-set_completion(colnr_T startcol, list_T *list)
-{
- int save_w_wrow = curwin->w_wrow;
- int save_w_leftcol = curwin->w_leftcol;
-
- /* If already doing completions stop it. */
- if (ctrl_x_mode != CTRL_X_NORMAL)
- ins_compl_prep(' ');
- ins_compl_clear();
- ins_compl_free();
-
- compl_direction = FORWARD;
- if (startcol > curwin->w_cursor.col)
- startcol = curwin->w_cursor.col;
- compl_col = startcol;
- compl_length = (int)curwin->w_cursor.col - (int)startcol;
- /* compl_pattern doesn't need to be set */
- compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
- if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
- -1, p_ic, NULL, NULL, 0, ORIGINAL_TEXT, FALSE) != OK)
- return;
-
- ctrl_x_mode = CTRL_X_EVAL;
-
- ins_compl_add_list(list);
- compl_matches = ins_compl_make_cyclic();
- compl_started = TRUE;
- compl_used_match = TRUE;
- compl_cont_status = 0;
-
- compl_curr_match = compl_first_match;
- if (compl_no_insert || compl_no_select)
- {
- ins_complete(K_DOWN, FALSE);
- if (compl_no_select)
- /* Down/Up has no real effect. */
- ins_complete(K_UP, FALSE);
- }
- else
- ins_complete(Ctrl_N, FALSE);
- compl_enter_selects = compl_no_insert;
-
- /* Lazily show the popup menu, unless we got interrupted. */
- if (!compl_interrupted)
- show_pum(save_w_wrow, save_w_leftcol);
- out_flush();
-}
-
-
-/* "compl_match_array" points the currently displayed list of entries in the
- * popup menu. It is NULL when there is no popup menu. */
-static pumitem_T *compl_match_array = NULL;
-static int compl_match_arraysize;
-
-/*
- * Update the screen and when there is any scrolling remove the popup menu.
- */
- static void
-ins_compl_upd_pum(void)
-{
- int h;
-
- if (compl_match_array != NULL)
- {
- h = curwin->w_cline_height;
- // Update the screen later, before drawing the popup menu over it.
- pum_call