diff options
| author | zeertzjq <zeertzjq@outlook.com> | 2022-07-20 06:33:55 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-20 06:33:55 +0800 |
| commit | 1ef84547a8ed4b237fbfbe673f1e9c4cd863ff0b (patch) | |
| tree | ce6987a5e351d2c4d529edfe1466d291efc75fe2 /src | |
| parent | 8620dfc5bdedc26e24119eb016d7e6121e9b49b6 (diff) | |
| parent | 420bb2eb8a583391c38a1e6d60132a70de21d99e (diff) | |
| download | rneovim-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.c | 1 | ||||
| -rw-r--r-- | src/nvim/autocmd.c | 1 | ||||
| -rw-r--r-- | src/nvim/change.c | 1 | ||||
| -rw-r--r-- | src/nvim/edit.c | 3797 | ||||
| -rw-r--r-- | src/nvim/edit.h | 20 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 59 | ||||
| -rw-r--r-- | src/nvim/eval/userfunc.c | 1 | ||||
| -rw-r--r-- | src/nvim/getchar.c | 1 | ||||
| -rw-r--r-- | src/nvim/globals.h | 4 | ||||
| -rw-r--r-- | src/nvim/insexpand.c | 3886 | ||||
| -rw-r--r-- | src/nvim/insexpand.h | 18 | ||||
| -rw-r--r-- | src/nvim/main.c | 1 | ||||
| -rw-r--r-- | src/nvim/memory.c | 2 | ||||
| -rw-r--r-- | src/nvim/option.c | 1 | ||||
| -rw-r--r-- | src/nvim/popupmnu.c | 1 | ||||
| -rw-r--r-- | src/nvim/screen.c | 1 | ||||
| -rw-r--r-- | src/nvim/search.c | 5 | ||||
| -rw-r--r-- | src/nvim/spell.c | 3 | ||||
| -rw-r--r-- | src/nvim/state.c | 2 | ||||
| -rw-r--r-- | src/nvim/tag.c | 3 |
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 ( |