aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-07-20 06:33:55 +0800
committerGitHub <noreply@github.com>2022-07-20 06:33:55 +0800
commit1ef84547a8ed4b237fbfbe673f1e9c4cd863ff0b (patch)
treece6987a5e351d2c4d529edfe1466d291efc75fe2 /src
parent8620dfc5bdedc26e24119eb016d7e6121e9b49b6 (diff)
parent420bb2eb8a583391c38a1e6d60132a70de21d99e (diff)
downloadrneovim-1ef84547a8ed4b237fbfbe673f1e9c4cd863ff0b.tar.gz
rneovim-1ef84547a8ed4b237fbfbe673f1e9c4cd863ff0b.tar.bz2
rneovim-1ef84547a8ed4b237fbfbe673f1e9c4cd863ff0b.zip
Merge pull request #19415 from zeertzjq/vim-8.1.1076
vim-patch:8.1.{1076,1849}: file for Insert mode is much too big
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/vim.c1
-rw-r--r--src/nvim/autocmd.c1
-rw-r--r--src/nvim/change.c1
-rw-r--r--src/nvim/edit.c3797
-rw-r--r--src/nvim/edit.h20
-rw-r--r--src/nvim/eval/funcs.c59
-rw-r--r--src/nvim/eval/userfunc.c1
-rw-r--r--src/nvim/getchar.c1
-rw-r--r--src/nvim/globals.h4
-rw-r--r--src/nvim/insexpand.c3886
-rw-r--r--src/nvim/insexpand.h18
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/memory.c2
-rw-r--r--src/nvim/option.c1
-rw-r--r--src/nvim/popupmnu.c1
-rw-r--r--src/nvim/screen.c1
-rw-r--r--src/nvim/search.c5
-rw-r--r--src/nvim/spell.c3
-rw-r--r--src/nvim/state.c2
-rw-r--r--src/nvim/tag.c3
20 files changed, 3968 insertions, 3840 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 5d941890db..51807c9ca8 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -37,6 +37,7 @@
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/mapping.h"
#include "nvim/mark.h"
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index d51079b515..159506a14a 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -18,6 +18,7 @@
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/insexpand.h"
#include "nvim/lua/executor.h"
#include "nvim/map.h"
#include "nvim/option.h"
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 4568b71fd9..22975d75d9 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -17,6 +17,7 @@
#include "nvim/fold.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/move.h"
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 0571e71cb5..6658f69dda 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -18,7 +18,6 @@
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
-#include "nvim/eval/typval.h"
#include "nvim/event/loop.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -29,6 +28,7 @@
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
#include "nvim/main.h"
#include "nvim/mapping.h"
@@ -48,180 +48,18 @@
#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
-#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/tag.h"
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/vim.h"
#include "nvim/window.h"
-// 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_CMDLINE_CTRL_X 17 ///< CTRL-X typed in CTRL_X_CMDLINE
-
-#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.
- N_(" Command-line completion (^V^N^P)"),
-};
-
-static char *ctrl_x_mode_names[] = {
- "keyword",
- "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",
- "cmdline",
-};
-
-static char e_hitend[] = N_("Hit end of paragraph");
-static char e_compldel[] = N_("E840: Completion function deleted text");
-
-/*
- * 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_u *(cp_text[CPT_COUNT]); // text for the menu
- typval_T cp_user_data;
- char_u *cp_fname; // file containing the match, allocated when
- // cp_flags has CP_FREE_FNAME
- int cp_flags; // CP_ values
- int cp_number; // sequence number
-};
-
-/*
- * 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 bool 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 bool 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 bool 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 bool compl_started = false;
-
-// Which Ctrl-X mode are we in?
-static int ctrl_x_mode = CTRL_X_NORMAL;
-
-static int compl_matches = 0;
-static char_u *compl_pattern = NULL;
-static Direction compl_direction = FORWARD;
-static Direction 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 bool compl_opt_refresh_always = false;
-
-static int pum_selected_item = -1;
-
-/// state for pum_ext_select_item.
-struct {
- bool active;
- int item;
- bool insert;
- bool finish;
-} pum_want;
-
typedef struct insert_state {
VimState state;
cmdarg_T *ca;
@@ -253,8 +91,6 @@ typedef struct insert_state {
#define BACKSPACE_WORD_NOT_SPACE 3
#define BACKSPACE_LINE 4
-static size_t spell_bad_len = 0; // length of located bad word
-
static colnr_T Insstart_textlen; // length of line when insert started
static colnr_T Insstart_blank_vcol; // vcol for first inserted blank
static bool update_Insstart_orig = true; // set Insstart_orig to Insstart
@@ -521,7 +357,7 @@ static int insert_check(VimState *state)
// If typed something may trigger CursorHoldI again.
if (s->c != K_EVENT
// but not in CTRL-X mode, a script can't restore the state
- && ctrl_x_mode == CTRL_X_NORMAL) {
+ && ctrl_x_mode_normal()) {
did_cursorhold = false;
}
@@ -532,8 +368,8 @@ static int insert_check(VimState *state)
if (can_cindent
&& cindent_on()
- && ctrl_x_mode == CTRL_X_NORMAL
- && !compl_started) {
+ && ctrl_x_mode_normal()
+ && !ins_compl_active()) {
insert_do_cindent(s);
}
@@ -551,7 +387,7 @@ static int insert_check(VimState *state)
Insstart_orig = Insstart;
}
- if (stop_insert_mode && !compl_started) {
+ if (stop_insert_mode && !ins_compl_active()) {
// ":stopinsert" used
s->count = 0;
return 0; // exit insert mode
@@ -688,29 +524,25 @@ static int insert_execute(VimState *state, int key)
// Special handling of keys while the popup menu is visible or wanted
// 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 ((s->c == K_BS || s->c == Ctrl_H)
- && curwin->w_cursor.col > compl_col
+ && curwin->w_cursor.col > ins_compl_col()
&& (s->c = ins_compl_bs()) == NUL) {
return 1; // 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 (s->c == Ctrl_L
- && (!CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
- || (compl_shown_match != NULL
- && compl_shown_match->cp_str != NULL
- && (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();
return 1; // continue
}
@@ -736,7 +568,7 @@ static int insert_execute(VimState *state, int key)
// Pressing CTRL-Y selects the current match. When
// compl_enter_selects is set the Enter key does the same.
if ((s->c == Ctrl_Y
- || (compl_enter_selects
+ || (ins_compl_enter_selects()
&& (s->c == CAR || s->c == K_KENTER || s->c == NL)))
&& stop_arrow() == OK) {
ins_compl_delete();
@@ -747,7 +579,7 @@ static int insert_execute(VimState *state, int key)
// 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(s->c)) {
return 1; // continue
}
@@ -779,8 +611,7 @@ static int insert_execute(VimState *state, int key)
s->c = do_digraph(s->c);
- if ((s->c == Ctrl_V || s->c == Ctrl_Q)
- && (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X)) {
+ if ((s->c == Ctrl_V || s->c == Ctrl_Q) && ctrl_x_mode_cmdline()) {
insert_do_complete(s);
return 1;
}
@@ -791,8 +622,7 @@ static int insert_execute(VimState *state, int key)
return 1; // continue
}
- if (cindent_on()
- && ctrl_x_mode == 0) {
+ if (cindent_on() && ctrl_x_mode_none()) {
// A key name preceded by a bang means this key is not to be
// inserted. Skip ahead to the re-indenting below.
// A key name preceded by a star means that indenting has to be
@@ -873,7 +703,7 @@ static int insert_handle_key(InsertState *s)
goto normalchar; // insert CTRL-Z as normal char
case Ctrl_O: // execute one command
- if (ctrl_x_mode == CTRL_X_OMNI) {
+ if (ctrl_x_mode_omni()) {
insert_do_complete(s);
break;
}
@@ -946,14 +776,14 @@ static int insert_handle_key(InsertState *s)
break;
case Ctrl_D: // Make indent one shiftwidth smaller.
- if (ctrl_x_mode == CTRL_X_PATH_DEFINES) {
+ if (ctrl_x_mode_path_defines()) {
insert_do_complete(s);
break;
}
FALLTHROUGH;
case Ctrl_T: // Make indent one shiftwidth greater.
- if (s->c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS) {
+ if (s->c == Ctrl_T && ctrl_x_mode_thesaurus()) {
if (check_compl_option(false)) {
insert_do_complete(s);
}
@@ -992,7 +822,7 @@ static int insert_handle_key(InsertState *s)
case Ctrl_U: // delete all inserted text in current line
// CTRL-X CTRL-U completes with 'completefunc'.
- if (ctrl_x_mode == CTRL_X_FUNCTION) {
+ if (ctrl_x_mode_function()) {
insert_do_complete(s);
} else {
s->did_backspace = ins_bs(s->c, BACKSPACE_LINE, &s->inserted_space);
@@ -1157,7 +987,7 @@ check_pum:
FALLTHROUGH;
case TAB: // TAB or Complete patterns along path
- if (ctrl_x_mode == CTRL_X_PATH_PATTERNS) {
+ if (ctrl_x_mode_path_patterns()) {
insert_do_complete(s);
break;
}
@@ -1205,7 +1035,7 @@ check_pum:
break;
case Ctrl_K: // digraph or keyword completion
- if (ctrl_x_mode == CTRL_X_DICTIONARY) {
+ if (ctrl_x_mode_dictionary()) {
if (check_compl_option(true)) {
insert_do_complete(s);
}
@@ -1223,7 +1053,7 @@ check_pum:
break;
case Ctrl_RSB: // Tag name completion after ^X
- if (ctrl_x_mode != CTRL_X_TAGS) {
+ if (!ctrl_x_mode_tags()) {
goto normalchar;
} else {
insert_do_complete(s);
@@ -1231,7 +1061,7 @@ check_pum:
break;
case Ctrl_F: // File name completion after ^X
- if (ctrl_x_mode != CTRL_X_FILES) {
+ if (!ctrl_x_mode_files()) {
goto normalchar;
} else {
insert_do_complete(s);
@@ -1240,7 +1070,7 @@ check_pum:
case 's': // Spelling completion after ^X
case Ctrl_S:
- if (ctrl_x_mode != CTRL_X_SPELL) {
+ if (!ctrl_x_mode_spell()) {
goto normalchar;
} else {
insert_do_complete(s);
@@ -1248,7 +1078,7 @@ check_pum:
break;
case Ctrl_L: // Whole line completion after ^X
- if (ctrl_x_mode != CTRL_X_WHOLE_LINE) {
+ if (!ctrl_x_mode_whole_line()) {
goto normalchar;
}
FALLTHROUGH;
@@ -1258,8 +1088,7 @@ check_pum:
// 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;
}
@@ -1409,7 +1238,7 @@ bool edit(int cmdchar, bool startln, long count)
// Don't allow changes in the buffer while editing the cmdline. The
// caller of getcmdline() may get confused.
// Don't allow recursive insert mode when busy with completion.
- if (textlock != 0 || compl_started || compl_busy || pum_visible()) {
+ if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) {
emsg(_(e_textlock));
return false;
}
@@ -1425,6 +1254,11 @@ bool edit(int cmdchar, bool startln, long count)
return s->c == Ctrl_O;
}
+bool 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'
/// option work correctly.
@@ -1432,7 +1266,7 @@ bool edit(int cmdchar, bool startln, long count)
/// inserting sequences of characters (e.g., for CTRL-R).
///
/// @param ready not busy with something
-static void ins_redraw(bool ready)
+void ins_redraw(bool ready)
{
if (char_avail()) {
return;
@@ -2019,3523 +1853,6 @@ static bool del_char_after_col(int limit_col)
return true;
}
-/*
- * CTRL-X pressed in Insert mode.
- */
-static void ins_ctrl_x(void)
-{
- if (ctrl_x_mode != CTRL_X_CMDLINE && ctrl_x_mode != CTRL_X_CMDLINE_CTRL_X) {
- // 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();
- } else {
- // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
- // CTRL-V look like CTRL-N
- ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
- }
-
- may_trigger_modechanged();
-}
-
-// Whether other than default completion has been selected.
-bool ctrl_x_mode_not_default(void)
- FUNC_ATTR_PURE
-{
- return ctrl_x_mode != CTRL_X_NORMAL;
-}
-
-// Whether CTRL-X was typed without a following character,
-// not including when in CTRL-X CTRL-V mode.
-bool ctrl_x_mode_not_defined_yet(void)
- FUNC_ATTR_PURE
-{
- return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
-}
-
-/// Check that the "dict" or "tsr" option can be used.
-///
-/// @param dict_opt check "dict" when true, "tsr" when false.
-static bool check_compl_option(bool dict_opt)
-{
- if (dict_opt
- ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
- : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL
- && *curbuf->b_p_tsrfu == NUL && *p_tsrfu == 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();
- ui_flush();
- os_delay(2004L, false);
- }
- return false;
- }
- return true;
-}
-
-/// Check that the character "c" a valid key to go to or keep us in CTRL-X mode?
-/// This depends on the current mode.
-///
-/// @param c character to check
-bool vim_is_ctrl_x_key(int c)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- // 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:
- case CTRL_X_CMDLINE_CTRL_X:
- 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'
- || c == Ctrl_Z;
- 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;
- 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;
- case CTRL_X_CMDLINE:
- return c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
- || c == Ctrl_X;
- 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;
- 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;
-}
-
-/// Check that character "c" is part of the item currently being
-/// completed. Used to decide whether to abandon complete mode when the menu
-/// is visible.
-///
-/// @param c character to check
-static bool ins_compl_accept_char(int c)
- FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
-{
- 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_CMDLINE_CTRL_X:
- 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) && !ascii_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
-///
-/// @param[in] cont_s_ipos next ^X<> will set initial_pos
-int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, Direction dir,
- bool cont_s_ipos)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- char_u *str = str_arg;
- int i, c;
- int actual_len; // Take multi-byte characters
- int actual_compl_length; // into account.
- int min_len;
- bool has_lower = false;
- bool was_letter = false;
- int flags = 0;
-
- if (p_ic && curbuf->b_p_inf && len > 0) {
- // Infer case of completed part.
-
- // Find actual length of completion.
- {
- const char_u *p = str;
- actual_len = 0;
- while (*p != NUL) {
- MB_PTR_ADV(p);
- actual_len++;
- }
- }
-
- // Find actual length of original text.
- {
- const char_u *p = compl_orig_text;
- actual_compl_length = 0;
- while (*p != NUL) {
- MB_PTR_ADV(p);
- actual_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.
- int *const wca = xmalloc((size_t)actual_len * sizeof(*wca));
- {
- const char_u *p = str;
- for (i = 0; i < actual_len; i++) {
- wca[i] = mb_ptr2char_adv(&p);
- }
- }
-
- // Rule 1: Were any chars converted to lower?
- {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&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) {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&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.
- {
- const char_u *p = compl_orig_text;
- for (i = 0; i < min_len; i++) {
- c = mb_ptr2char_adv(&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.
- {
- char_u *p = IObuff;
- i = 0;
- while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
- p += utf_char2bytes(wca[i++], (char *)p);
- }
- *p = NUL;
- }
-
- xfree(wca);
-
- str = IObuff;
- }
- if (cont_s_ipos) {
- flags |= CP_CONT_S_IPOS;
- }
- if (icase) {
- flags |= CP_ICASE;
- }
-
- return ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false);
-}
-
-/// Add a match to the list of matches
-///
-/// @param[in] str Match to add.
-/// @param[in] len Match length, -1 to use #STRLEN.
-/// @param[in] fname File name match comes from. May be NULL.
-/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
-/// must have exactly #CPT_COUNT items.
-/// @param[in] cptext_allocated If true, will not copy cptext strings.
-///
-/// @note Will free strings in case of error.
-/// cptext itself will not be freed.
-/// @param[in] cdir Completion direction.
-/// @param[in] adup True if duplicate matches are to be accepted.
-///
-/// @return NOTDONE if the given string is already in the list of completions,
-/// otherwise it is added to the list and OK is returned. FAIL will be
-/// returned in case of error.
-static int ins_compl_add(char_u *const str, int len, char_u *const fname,
- char_u *const *const cptext, const bool cptext_allocated,
- typval_T *user_data, const Direction cdir, int flags_arg, const bool adup)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- compl_T *match;
- const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
- int flags = flags_arg;
-
- if (flags & CP_FAST) {
- fast_breakcheck();
- } else {
- os_breakcheck();
- }
-#define FREE_CPTEXT(cptext, cptext_allocated) \
- do { \
- if ((cptext) != NULL && (cptext_allocated)) { \
- for (size_t i = 0; i < CPT_COUNT; i++) { \
- xfree((cptext)[i]); \
- } \
- } \
- } while (0)
- if (got_int) {
- FREE_CPTEXT(cptext, cptext_allocated);
- 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 & CP_ORIGINAL_TEXT)
- && STRNCMP(match->cp_str, str, len) == 0
- && match->cp_str[len] == NUL) {
- FREE_CPTEXT(cptext, cptext_allocated);
- 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 = xcalloc(1, sizeof(compl_T));
- match->cp_number = -1;
- if (flags & CP_ORIGINAL_TEXT) {
- match->cp_number = 0;
- }
- match->cp_str = vim_strnsave(str, (size_t)len);
-
- // match-fname is:
- // - compl_curr_match->cp_fname if it is a string equal to fname.
- // - a copy of fname, CP_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 |= CP_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) {
- continue;
- }
- if (*cptext[i] != NUL) {
- match->cp_text[i] = (cptext_allocated
- ? cptext[i]
- : (char_u *)xstrdup((char *)cptext[i]));
- } else if (cptext_allocated) {
- xfree(cptext[i]);
- }
- }
- }
-
- if (