aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/insexpand.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/insexpand.c')
-rw-r--r--src/nvim/insexpand.c721
1 files changed, 430 insertions, 291 deletions
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index bd7ee55722..e21433f5ec 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -10,6 +10,7 @@
#include <string.h>
#include "klib/kvec.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/autocmd_defs.h"
@@ -37,7 +38,6 @@
#include "nvim/getchar.h"
#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
-#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
#include "nvim/indent.h"
@@ -156,7 +156,8 @@ typedef struct compl_S compl_T;
struct compl_S {
compl_T *cp_next;
compl_T *cp_prev;
- char *cp_str; ///< matched text
+ compl_T *cp_match_next; ///< matched next compl_T
+ String cp_str; ///< matched text
char *(cp_text[CPT_COUNT]); ///< text for the menu
typval_T cp_user_data;
char *cp_fname; ///< file containing the match, allocated when
@@ -164,6 +165,7 @@ struct compl_S {
int cp_flags; ///< CP_ values
int cp_number; ///< sequence number
int cp_score; ///< fuzzy match score
+ bool cp_in_match_array; ///< collected by compl_match_array
int cp_user_abbr_hlattr; ///< highlight attribute for abbr
int cp_user_kind_hlattr; ///< highlight attribute for kind
};
@@ -219,7 +221,7 @@ static bool compl_enter_selects = false;
/// When "compl_leader" is not NULL only matches that start with this string
/// are used.
-static char *compl_leader = NULL;
+static String compl_leader = STRING_INIT;
static bool compl_get_longest = false; ///< put longest common string in compl_leader
@@ -244,8 +246,7 @@ static bool compl_started = false;
static int ctrl_x_mode = CTRL_X_NORMAL;
static int compl_matches = 0; ///< number of completion matches
-static char *compl_pattern = NULL;
-static size_t compl_patternlen = 0;
+static String compl_pattern = STRING_INIT;
static Direction compl_direction = FORWARD;
static Direction compl_shows_dir = FORWARD;
static int compl_pending = 0; ///< > 1 for postponed CTRL-N
@@ -255,8 +256,9 @@ static pos_T compl_startpos;
static int compl_length = 0;
static colnr_T compl_col = 0; ///< column where the text starts
///< that is being completed
-static char *compl_orig_text = NULL; ///< text as it was before
- ///< completion started
+static colnr_T compl_ins_end_col = 0;
+static String compl_orig_text = STRING_INIT; ///< text as it was before
+ ///< completion started
/// Undo information to restore extmarks for original text.
static extmark_undo_vec_t compl_orig_extmarks;
static int compl_cont_mode = 0;
@@ -281,6 +283,11 @@ static size_t spell_bad_len = 0; // length of located bad word
static int compl_selected_item = -1;
+// "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;
+
/// CTRL-X pressed in Insert mode.
void ins_ctrl_x(void)
{
@@ -475,7 +482,7 @@ bool check_compl_option(bool dict_opt)
msg((dict_opt ? _("'dictionary' option is empty") : _("'thesaurus' option is empty")),
HLF_E);
if (emsg_silent == 0 && !in_assert_fails) {
- vim_beep(BO_COMPL);
+ vim_beep(kOptBoFlagComplete);
setcursor();
ui_flush();
os_delay(2004, false);
@@ -560,11 +567,19 @@ static bool is_first_match(const compl_T *const match)
return match == compl_first_match;
}
-static void do_autocmd_completedone(int c)
+static void do_autocmd_completedone(int c, int mode, char *word)
{
save_v_event_T save_v_event;
dict_T *v_event = get_v_event(&save_v_event);
+ mode = mode & ~CTRL_X_WANT_IDENT;
+ char *mode_str = NULL;
+ if (ctrl_x_mode_names[mode]) {
+ mode_str = ctrl_x_mode_names[mode];
+ }
+ tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : "");
+ tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : "");
+
tv_dict_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel"));
tv_dict_set_keys_readonly(v_event);
@@ -624,7 +639,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp
// Rule 1: Were any chars converted to lower?
{
- const char *p = compl_orig_text;
+ const char *p = compl_orig_text.data;
for (int i = 0; i < min_len; i++) {
const int c = mb_ptr2char_adv(&p);
if (mb_islower(c)) {
@@ -644,7 +659,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp
// upper case.
if (!has_lower) {
bool was_letter = false;
- const char *p = compl_orig_text;
+ const char *p = compl_orig_text.data;
for (int i = 0; i < min_len; i++) {
const int c = mb_ptr2char_adv(&p);
if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
@@ -660,7 +675,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp
// Copy the original case of the part we typed.
{
- const char *p = compl_orig_text;
+ const char *p = compl_orig_text.data;
for (int i = 0; i < min_len; i++) {
const int c = mb_ptr2char_adv(&p);
if (mb_islower(c)) {
@@ -690,7 +705,7 @@ static char *ins_compl_infercase_gettext(const char *str, int char_len, int comp
ga_grow(&gap, IOSIZE);
*p = NUL;
STRCPY(gap.ga_data, IObuff);
- gap.ga_len = (int)strlen(IObuff);
+ gap.ga_len = (int)(p - IObuff);
} else {
p += utf_char2bytes(wca[i++], p);
}
@@ -737,7 +752,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir
// Find actual length of original text.
{
- const char *p = compl_orig_text;
+ const char *p = compl_orig_text.data;
compl_char_len = 0;
while (*p != NUL) {
MB_PTR_ADV(p);
@@ -747,7 +762,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir
// "char_len" may be smaller than "compl_char_len" when using
// thesaurus, only use the minimum when comparing.
- int min_len = char_len < compl_char_len ? char_len : compl_char_len;
+ int min_len = MIN(char_len, compl_char_len);
str = ins_compl_infercase_gettext(str, char_len, compl_char_len, min_len, &tofree);
}
@@ -758,7 +773,7 @@ int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Dir
flags |= CP_ICASE;
}
- int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, -1, -1);
+ int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, NULL);
xfree(tofree);
return res;
}
@@ -789,6 +804,7 @@ static inline void free_cptext(char *const *const cptext)
/// @param[in] cdir match direction. If 0, use "compl_direction".
/// @param[in] flags_arg match flags (cp_flags)
/// @param[in] adup accept this match even if it is already present.
+/// @param[in] user_hl list of extra highlight attributes for abbr kind.
///
/// If "cdir" is FORWARD, then the match is added after the current match.
/// Otherwise, it is added before the current match.
@@ -798,7 +814,7 @@ static inline void free_cptext(char *const *const cptext)
/// returned in case of error.
static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext,
const bool cptext_allocated, typval_T *user_data, const Direction cdir,
- int flags_arg, const bool adup, int user_abbr_hlattr, int user_kind_hlattr)
+ int flags_arg, const bool adup, const int *user_hl)
FUNC_ATTR_NONNULL_ARG(1)
{
compl_T *match;
@@ -825,8 +841,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
match = compl_first_match;
do {
if (!match_at_original_text(match)
- && strncmp(match->cp_str, str, (size_t)len) == 0
- && ((int)strlen(match->cp_str) <= len || match->cp_str[len] == NUL)) {
+ && strncmp(match->cp_str.data, str, (size_t)len) == 0
+ && ((int)match->cp_str.size <= len || match->cp_str.data[len] == NUL)) {
if (cptext_allocated) {
free_cptext(cptext);
}
@@ -846,7 +862,7 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
if (flags & CP_ORIGINAL_TEXT) {
match->cp_number = 0;
}
- match->cp_str = xstrnsave(str, (size_t)len);
+ match->cp_str = cbuf_to_string(str, (size_t)len);
// match-fname is:
// - compl_curr_match->cp_fname if it is a string equal to fname.
@@ -864,8 +880,8 @@ static int ins_compl_add(char *const str, int len, char *const fname, char *cons
match->cp_fname = NULL;
}
match->cp_flags = flags;
- match->cp_user_abbr_hlattr = user_abbr_hlattr;
- match->cp_user_kind_hlattr = user_kind_hlattr;
+ match->cp_user_abbr_hlattr = user_hl ? user_hl[0] : -1;
+ match->cp_user_kind_hlattr = user_hl ? user_hl[1] : -1;
if (cptext != NULL) {
int i;
@@ -928,27 +944,55 @@ static bool ins_compl_equal(compl_T *match, char *str, size_t len)
return true;
}
if (match->cp_flags & CP_ICASE) {
- return STRNICMP(match->cp_str, str, len) == 0;
+ return STRNICMP(match->cp_str.data, str, len) == 0;
+ }
+ return strncmp(match->cp_str.data, str, len) == 0;
+}
+
+/// when len is -1 mean use whole length of p otherwise part of p
+static void ins_compl_insert_bytes(char *p, int len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (len == -1) {
+ len = (int)strlen(p);
}
- return strncmp(match->cp_str, str, len) == 0;
+ assert(len >= 0);
+ ins_bytes_len(p, (size_t)len);
+ compl_ins_end_col = curwin->w_cursor.col;
+}
+
+/// Checks if the column is within the currently inserted completion text
+/// column range. If it is, it returns a special highlight attribute.
+/// -1 mean normal item.
+int ins_compl_col_range_attr(int col)
+{
+ if (get_cot_flags() & kOptCotFlagFuzzy) {
+ return -1;
+ }
+
+ if (col >= (compl_col + (int)ins_compl_leader_len()) && col < compl_ins_end_col) {
+ return syn_name2attr("ComplMatchIns");
+ }
+
+ return -1;
}
/// Reduce the longest common string for match "match".
static void ins_compl_longest_match(compl_T *match)
{
- if (compl_leader == NULL) {
+ if (compl_leader.data == NULL) {
// First match, use it as a whole.
- compl_leader = xstrdup(match->cp_str);
+ compl_leader = copy_string(match->cp_str, NULL);
bool had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + get_compl_len());
+ ins_compl_delete(false);
+ ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
// again after redrawing.
if (!had_match) {
- ins_compl_delete();
+ ins_compl_delete(false);
}
compl_used_match = false;
@@ -956,8 +1000,8 @@ static void ins_compl_longest_match(compl_T *match)
}
// Reduce the text if this match differs from compl_leader.
- char *p = compl_leader;
- char *s = match->cp_str;
+ char *p = compl_leader.data;
+ char *s = match->cp_str.data;
while (*p != NUL) {
int c1 = utf_ptr2char(p);
int c2 = utf_ptr2char(s);
@@ -974,15 +1018,17 @@ static void ins_compl_longest_match(compl_T *match)
if (*p != NUL) {
// Leader was shortened, need to change the inserted text.
*p = NUL;
+ compl_leader.size = (size_t)(p - compl_leader.data);
+
bool had_match = (curwin->w_cursor.col > compl_col);
- ins_compl_delete();
- ins_bytes(compl_leader + get_compl_len());
+ ins_compl_delete(false);
+ ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it
// again after redrawing.
if (!had_match) {
- ins_compl_delete();
+ ins_compl_delete(false);
}
}
@@ -997,9 +1043,9 @@ static void ins_compl_add_matches(int num_matches, char **matches, int icase)
Direction dir = compl_direction;
for (int i = 0; i < num_matches && add_r != FAIL; i++) {
- if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
- CP_FAST | (icase ? CP_ICASE : 0),
- false, -1, -1)) == OK) {
+ add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir,
+ CP_FAST | (icase ? CP_ICASE : 0), false, NULL);
+ if (add_r == OK) {
// If dir was BACKWARD then honor it just once.
dir = FORWARD;
}
@@ -1038,8 +1084,8 @@ bool ins_compl_has_shown_match(void)
/// Return whether the shown match is long enough.
bool ins_compl_long_shown_match(void)
{
- return compl_shown_match != NULL && compl_shown_match->cp_str != NULL
- && (colnr_T)strlen(compl_shown_match->cp_str) > curwin->w_cursor.col - compl_col;
+ return compl_shown_match != NULL && compl_shown_match->cp_str.data != NULL
+ && (colnr_T)compl_shown_match->cp_str.size > curwin->w_cursor.col - compl_col;
}
/// Get the local or global value of 'completeopt' flags.
@@ -1048,11 +1094,6 @@ unsigned get_cot_flags(void)
return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags;
}
-/// "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;
-
/// Remove any popup menu.
static void ins_compl_del_pum(void)
{
@@ -1069,7 +1110,7 @@ bool pum_wanted(void)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// "completeopt" must contain "menu" or "menuone"
- return (get_cot_flags() & COT_ANY_MENU) != 0;
+ return (get_cot_flags() & (kOptCotFlagMenu | kOptCotFlagMenuone)) != 0;
}
/// Check that there are two or more matches to be shown in the popup menu.
@@ -1088,7 +1129,7 @@ static bool pum_enough_matches(void)
comp = comp->cp_next;
} while (!is_first_match(comp));
- if (get_cot_flags() & COT_MENUONE) {
+ if (get_cot_flags() & kOptCotFlagMenuone) {
return i >= 1;
}
return i >= 2;
@@ -1099,7 +1140,7 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
{
// { word, abbr, menu, kind, info }
dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
- tv_dict_add_str(dict, S_LEN("word"), match->cp_str);
+ tv_dict_add_str(dict, S_LEN("word"), match->cp_str.data);
tv_dict_add_str(dict, S_LEN("abbr"), match->cp_text[CPT_ABBR]);
tv_dict_add_str(dict, S_LEN("menu"), match->cp_text[CPT_MENU]);
tv_dict_add_str(dict, S_LEN("kind"), match->cp_text[CPT_KIND]);
@@ -1168,54 +1209,47 @@ static int ins_compl_build_pum(void)
XFREE_CLEAR(compl_leader);
}
- const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0;
int max_fuzzy_score = 0;
unsigned cur_cot_flags = get_cot_flags();
- bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
- bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
-
- do {
- // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
- // set the cp_score for later comparisons.
- if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
- comp->cp_score = fuzzy_match_str(comp->cp_str, compl_leader);
- }
-
- if (!match_at_original_text(comp)
- && (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
- || (compl_fuzzy_match && comp->cp_score > 0))) {
- compl_match_arraysize++;
- }
- comp = comp->cp_next;
- } while (comp != NULL && !is_first_match(comp));
-
- if (compl_match_arraysize == 0) {
- return -1;
- }
-
- assert(compl_match_arraysize >= 0);
- compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
+ bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0;
+ bool fuzzy_filter = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
+ bool fuzzy_sort = fuzzy_filter && !(cur_cot_flags & kOptCotFlagNosort);
+ compl_T *match_head = NULL, *match_tail = NULL;
// If the current match is the original text don't find the first
// match after it, don't highlight anything.
bool shown_match_ok = match_at_original_text(compl_shown_match);
- if (strequal(compl_leader, compl_orig_text) && !shown_match_ok) {
+ if (strequal(compl_leader.data, compl_orig_text.data) && !shown_match_ok) {
compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next;
}
- compl_T *shown_compl = NULL;
bool did_find_shown_match = false;
- int cur = -1;
+ compl_T *shown_compl = NULL;
int i = 0;
- comp = compl_first_match;
+ int cur = -1;
+
do {
+ comp->cp_in_match_array = false;
+ // When 'completeopt' contains "fuzzy" and leader is not NULL or empty,
+ // set the cp_score for later comparisons.
+ if (fuzzy_filter && compl_leader.data != NULL && compl_leader.size > 0) {
+ comp->cp_score = fuzzy_match_str(comp->cp_str.data, compl_leader.data);
+ }
+
if (!match_at_original_text(comp)
- && (compl_leader == NULL
- || ins_compl_equal(comp, compl_leader, (size_t)lead_len)
- || (compl_fuzzy_match && comp->cp_score > 0))) {
- if (!shown_match_ok && !compl_fuzzy_match) {
+ && (compl_leader.data == NULL
+ || ins_compl_equal(comp, compl_leader.data, compl_leader.size)
+ || (fuzzy_filter && comp->cp_score > 0))) {
+ compl_match_arraysize++;
+ comp->cp_in_match_array = true;
+ if (match_head == NULL) {
+ match_head = comp;
+ } else {
+ match_tail->cp_match_next = comp;
+ }
+ match_tail = comp;
+ if (!shown_match_ok && !fuzzy_filter) {
if (comp == compl_shown_match || did_find_shown_match) {
// This item is the shown match or this is the
// first displayed item after the shown match.
@@ -1228,64 +1262,36 @@ static int ins_compl_build_pum(void)
shown_compl = comp;
}
cur = i;
- } else if (compl_fuzzy_match) {
+ } else if (fuzzy_filter) {
if (i == 0) {
shown_compl = comp;
}
// Update the maximum fuzzy score and the shown match
// if the current item's score is higher
- if (comp->cp_score > max_fuzzy_score) {
+ if (fuzzy_sort && comp->cp_score > max_fuzzy_score) {
did_find_shown_match = true;
max_fuzzy_score = comp->cp_score;
if (!compl_no_select) {
compl_shown_match = comp;
}
+ } else if (!fuzzy_sort && i == 0 && !compl_no_select) {
+ compl_shown_match = shown_compl;
}
-
if (!shown_match_ok && comp == compl_shown_match && !compl_no_select) {
cur = i;
shown_match_ok = true;
}
-
- // If there is no "no select" condition and the max fuzzy
- // score is positive, or there is no completion leader or the
- // leader length is zero, mark the shown match as valid and
- // reset the current index.
- if (!compl_no_select
- && (max_fuzzy_score > 0
- || (compl_leader == NULL || lead_len == 0))) {
- if (match_at_original_text(compl_shown_match)) {
- compl_shown_match = shown_compl;
- }
- }
- }
-
- if (comp->cp_text[CPT_ABBR] != NULL) {
- compl_match_array[i].pum_text = comp->cp_text[CPT_ABBR];
- } else {
- compl_match_array[i].pum_text = comp->cp_str;
- }
- compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
- compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
- compl_match_array[i].pum_score = comp->cp_score;
- compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr;
- compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr;
- if (comp->cp_text[CPT_MENU] != NULL) {
- compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU];
- } else {
- compl_match_array[i++].pum_extra = comp->cp_fname;
}
+ i++;
}
- if (comp == compl_shown_match && !compl_fuzzy_match) {
+ if (comp == compl_shown_match && !fuzzy_filter) {
did_find_shown_match = true;
-
// When the original text is the shown match don't set
// compl_shown_match.
if (match_at_original_text(comp)) {
shown_match_ok = true;
}
-
if (!shown_match_ok && shown_compl != NULL) {
// The shown match isn't displayed, set it to the
// previously displayed match.
@@ -1296,7 +1302,31 @@ static int ins_compl_build_pum(void)
comp = comp->cp_next;
} while (comp != NULL && !is_first_match(comp));
- if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) {
+ if (compl_match_arraysize == 0) {
+ return -1;
+ }
+
+ assert(compl_match_arraysize >= 0);
+ compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T));
+
+ i = 0;
+ comp = match_head;
+ while (comp != NULL) {
+ compl_match_array[i].pum_text = comp->cp_text[CPT_ABBR] != NULL
+ ? comp->cp_text[CPT_ABBR] : comp->cp_str.data;
+ compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
+ compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
+ compl_match_array[i].pum_score = comp->cp_score;
+ compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr;
+ compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr;
+ compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU] != NULL
+ ? comp->cp_text[CPT_MENU] : comp->cp_fname;
+ compl_T *match_next = comp->cp_match_next;
+ comp->cp_match_next = NULL;
+ comp = match_next;
+ }
+
+ if (fuzzy_sort && compl_leader.data != NULL && compl_leader.size > 0) {
for (i = 0; i < compl_match_arraysize; i++) {
compl_match_array[i].pum_idx = i;
}
@@ -1334,7 +1364,7 @@ void ins_compl_show_pum(void)
} else {
// popup menu already exists, only need to find the current item.
for (int i = 0; i < compl_match_arraysize; i++) {
- if (compl_match_array[i].pum_text == compl_shown_match->cp_str
+ if (compl_match_array[i].pum_text == compl_shown_match->cp_str.data
|| compl_match_array[i].pum_text == compl_shown_match->cp_text[CPT_ABBR]) {
cur = i;
break;
@@ -1403,7 +1433,13 @@ bool compl_match_curr_select(int selected)
/// Get current completion leader
char *ins_compl_leader(void)
{
- return compl_leader != NULL ? compl_leader : compl_orig_text;
+ return compl_leader.data != NULL ? compl_leader.data : compl_orig_text.data;
+}
+
+/// Get current completion leader length
+size_t ins_compl_leader_len(void)
+{
+ return compl_leader.data != NULL ? compl_leader.size : compl_orig_text.size;
}
/// Add any identifiers that match the given pattern "pat" in the list of
@@ -1562,6 +1598,7 @@ static void ins_compl_files(int count, char **files, bool thesaurus, int flags,
FILE *fp = os_fopen(files[i], "r"); // open dictionary file
if (flags != DICT_EXACT && !shortmess(SHM_COMPLETIONSCAN)) {
msg_hist_off = true; // reset in msg_trunc()
+ msg_ext_set_kind("completion");
vim_snprintf(IObuff, IOSIZE,
_("Scanning dictionary: %s"), files[i]);
msg_trunc(IObuff, true, HLF_R);
@@ -1577,11 +1614,7 @@ static void ins_compl_files(int count, char **files, bool thesaurus, int flags,
char *ptr = buf;
while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf))) {
ptr = regmatch->startp[0];
- if (ctrl_x_mode_line_or_eval()) {
- ptr = find_line_end(ptr);
- } else {
- ptr = find_word_end(ptr);
- }
+ ptr = ctrl_x_mode_line_or_eval() ? find_line_end(ptr) : find_word_end(ptr);
int add_r = ins_compl_add_infercase(regmatch->startp[0],
(int)(ptr - regmatch->startp[0]),
p_ic, files[i], *dir, false);
@@ -1652,9 +1685,8 @@ static char *find_line_end(char *ptr)
/// Free the list of completions
static void ins_compl_free(void)
{
- XFREE_CLEAR(compl_pattern);
- compl_patternlen = 0;
- XFREE_CLEAR(compl_leader);
+ API_CLEAR_STRING(compl_pattern);
+ API_CLEAR_STRING(compl_leader);
if (compl_first_match == NULL) {
return;
@@ -1667,7 +1699,7 @@ static void ins_compl_free(void)
do {
compl_T *match = compl_curr_match;
compl_curr_match = compl_curr_match->cp_next;
- xfree(match->cp_str);
+ API_CLEAR_STRING(match->cp_str);
// several entries may use the same fname, free it just once.
if (match->cp_flags & CP_FREE_FNAME) {
xfree(match->cp_fname);
@@ -1687,12 +1719,12 @@ void ins_compl_clear(void)
compl_cont_status = 0;
compl_started = false;
compl_matches = 0;
- XFREE_CLEAR(compl_pattern);
- compl_patternlen = 0;
- XFREE_CLEAR(compl_leader);
+ compl_ins_end_col = 0;
+ API_CLEAR_STRING(compl_pattern);
+ API_CLEAR_STRING(compl_leader);
edit_submode_extra = NULL;
kv_destroy(compl_orig_extmarks);
- XFREE_CLEAR(compl_orig_text);
+ API_CLEAR_STRING(compl_orig_text);
compl_enter_selects = false;
// clear v:completed_item
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
@@ -1705,6 +1737,12 @@ bool ins_compl_active(void)
return compl_started;
}
+/// Return true when wp is the actual completion window
+bool ins_compl_win_active(win_T *wp)
+{
+ return ins_compl_active() && !(wp->w_p_pvw || wp->w_float_is_info);
+}
+
/// Selected one of the matches. When false the match was edited or using the
/// longest common string.
bool ins_compl_used_match(void)
@@ -1743,12 +1781,33 @@ int ins_compl_len(void)
return compl_length;
}
+/// Return true when preinsert is set otherwise FALSE.
+static bool ins_compl_has_preinsert(void)
+{
+ return (get_cot_flags() & (kOptCotFlagFuzzy|kOptCotFlagPreinsert)) == kOptCotFlagPreinsert;
+}
+
+/// Returns true if the pre-insert effect is valid and the cursor is within
+/// the `compl_ins_end_col` range.
+bool ins_compl_preinsert_effect(void)
+{
+ if (!ins_compl_has_preinsert()) {
+ return false;
+ }
+
+ return curwin->w_cursor.col < compl_ins_end_col;
+}
+
/// Delete one character before the cursor and show the subset of the matches
/// that match the word that is now before the cursor.
/// Returns the character to be used, NUL if the work is done and another char
/// to be got from the user.
int ins_compl_bs(void)
{
+ if (ins_compl_preinsert_effect()) {
+ ins_compl_delete(false);
+ }
+
char *line = get_cursor_line_ptr();
char *p = line + curwin->w_cursor.col;
MB_PTR_BACK(line, p);
@@ -1776,8 +1835,9 @@ int ins_compl_bs(void)
// TODO(bfredl): get rid of random update_screen() calls deep inside completion logic
line = get_cursor_line_ptr();
- xfree(compl_leader);
- compl_leader = xstrnsave(line + compl_col, (size_t)(p_off - (ptrdiff_t)compl_col));
+ API_CLEAR_STRING(compl_leader);
+ compl_leader = cbuf_to_string(line + compl_col,
+ (size_t)(p_off - (ptrdiff_t)compl_col));
ins_compl_new_leader();
if (compl_shown_match != NULL) {
@@ -1810,12 +1870,12 @@ static bool ins_compl_need_restart(void)
static void ins_compl_new_leader(void)
{
ins_compl_del_pum();
- ins_compl_delete();
- ins_bytes(compl_leader + get_compl_len());
+ ins_compl_delete(true);
+ ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
compl_used_match = false;
if (compl_started) {
- ins_compl_set_original_text(compl_leader);
+ ins_compl_set_original_text(compl_leader.data, compl_leader.size);
} else {
spell_bad_len = 0; // need to redetect bad word
// Matches were cleared, need to search for them now.
@@ -1833,8 +1893,13 @@ static void ins_compl_new_leader(void)
ins_compl_show_pum();
// Don't let Enter select the original text when there is no popup menu.
+ if (compl_match_array == NULL) {
+ compl_enter_selects = false;
+ } else if (ins_compl_has_preinsert() && compl_leader.size > 0) {
+ ins_compl_insert(false, true);
+ }
// Don't let Enter select when use user function and refresh_always is set
- if (compl_match_array == NULL || ins_compl_refresh_always()) {
+ if (ins_compl_refresh_always()) {
compl_enter_selects = false;
}
}
@@ -1857,6 +1922,10 @@ void ins_compl_addleader(int c)
{
int cc;
+ if (ins_compl_preinsert_effect()) {
+ ins_compl_delete(false);
+ }
+
if (stop_arrow() == FAIL) {
return;
}
@@ -1875,9 +1944,9 @@ void ins_compl_addleader(int c)
ins_compl_restart();
}
- xfree(compl_leader);
- compl_leader = xstrnsave(get_cursor_line_ptr() + compl_col,
- (size_t)(curwin->w_cursor.col - compl_col));
+ API_CLEAR_STRING(compl_leader);
+ compl_leader = cbuf_to_string(get_cursor_line_ptr() + compl_col,
+ (size_t)(curwin->w_cursor.col - compl_col));
ins_compl_new_leader();
}
@@ -1897,19 +1966,19 @@ static void ins_compl_restart(void)
}
/// Set the first match, the original text.
-static void ins_compl_set_original_text(char *str)
+static void ins_compl_set_original_text(char *str, size_t len)
FUNC_ATTR_NONNULL_ALL
{
// Replace the original text entry.
// The CP_ORIGINAL_TEXT flag is either at the first item or might possibly
// be at the last item for backward completion
if (match_at_original_text(compl_first_match)) { // safety check
- xfree(compl_first_match->cp_str);
- compl_first_match->cp_str = xstrdup(str);
+ API_CLEAR_STRING(compl_first_match->cp_str);
+ compl_first_match->cp_str = cbuf_to_string(str, len);
} else if (compl_first_match->cp_prev != NULL
&& match_at_original_text(compl_first_match->cp_prev)) {
- xfree(compl_first_match->cp_prev->cp_str);
- compl_first_match->cp_prev->cp_str = xstrdup(str);
+ API_CLEAR_STRING(compl_first_match->cp_prev->cp_str);
+ compl_first_match->cp_prev->cp_str = cbuf_to_string(str, len);
}
}
@@ -1919,8 +1988,8 @@ void ins_compl_addfrommatch(void)
{
int len = (int)curwin->w_cursor.col - (int)compl_col;
assert(compl_shown_match != NULL);
- char *p = compl_shown_match->cp_str;
- if ((int)strlen(p) <= len) { // the match is too short
+ char *p = compl_shown_match->cp_str.data;
+ if ((int)compl_shown_match->cp_str.size <= len) { // the match is too short
// When still at the original match use the first entry that matches
// the leader.
if (!match_at_original_text(compl_shown_match)) {
@@ -1928,15 +1997,17 @@ void ins_compl_addfrommatch(void)
}
p = NULL;
+ size_t plen = 0;
for (compl_T *cp = compl_shown_match->cp_next; cp != NULL
&& !is_first_match(cp); cp = cp->cp_next) {
- if (compl_leader == NULL
- || ins_compl_equal(cp, compl_leader, strlen(compl_leader))) {
- p = cp->cp_str;
+ if (compl_leader.data == NULL
+ || ins_compl_equal(cp, compl_leader.data, compl_leader.size)) {
+ p = cp->cp_str.data;
+ plen = cp->cp_str.size;
break;
}
}
- if (p == NULL || (int)strlen(p) <= len) {
+ if (p == NULL || (int)plen <= len) {
return;
}
}
@@ -2076,7 +2147,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
// Get here when we have finished typing a sequence of ^N and
// ^P or other completion characters in CTRL-X mode. Free up
// memory that was used, and make sure we can redo the insert.
- if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E) {
+ if (compl_curr_match != NULL || compl_leader.data != NULL || c == Ctrl_E) {
// If any of the original typed text has been changed, eg when
// ignorecase is set, we must add back-spaces to the redo
// buffer. We add as few as necessary to delete just the part
@@ -2085,7 +2156,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
// CTRL-E then don't use the current match.
char *ptr;
if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) {
- ptr = compl_curr_match->cp_str;
+ ptr = compl_curr_match->cp_str.data;
} else {
ptr = NULL;
}
@@ -2121,36 +2192,46 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
}
+ char *word = NULL;
// If the popup menu is displayed pressing CTRL-Y means accepting
// the selection without inserting anything. When
// compl_enter_selects is set the Enter key does the same.
if ((c == Ctrl_Y || (compl_enter_selects
&& (c == CAR || c == K_KENTER || c == NL)))
&& pum_visible()) {
+ word = xstrdup(compl_shown_match->cp_str.data);
retval = true;
+ // May need to remove ComplMatchIns highlight.
+ redrawWinline(curwin, curwin->w_cursor.lnum);
}
// CTRL-E means completion is Ended, go back to the typed text.
// but only do this, if the Popup is still visible
if (c == Ctrl_E) {
- ins_compl_delete();
+ ins_compl_delete(false);
char *p = NULL;
- if (compl_leader != NULL) {
- p = compl_leader;
+ size_t plen = 0;
+ if (compl_leader.data != NULL) {
+ p = compl_leader.data;
+ plen = compl_leader.size;
} else if (compl_first_match != NULL) {
- p = compl_orig_text;
+ p = compl_orig_text.data;
+ plen = compl_orig_text.size;
}
if (p != NULL) {
const int compl_len = get_compl_len();
- const int len = (int)strlen(p);
- if (len > compl_len) {
- ins_bytes_len(p + compl_len, (size_t)(len - compl_len));
+ if ((int)plen > compl_len) {
+ ins_compl_insert_bytes(p + compl_len, (int)plen - compl_len);
}
}
restore_orig_extmarks();
retval = true;
}
+ if ((c == Ctrl_W || c == Ctrl_U) && ins_compl_preinsert_effect()) {
+ ins_compl_delete(false);
+ }
+
auto_format(false, true);
// Trigger the CompleteDonePre event to give scripts a chance to
@@ -2184,7 +2265,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
}
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, prev_mode, word);
+ xfree(word);
return retval;
}
@@ -2236,7 +2318,7 @@ bool ins_compl_prep(int c)
// Set "compl_get_longest" when finding the first matches.
if (ctrl_x_mode_not_defined_yet()
|| (ctrl_x_mode_normal() && !compl_started)) {
- compl_get_longest = (get_cot_flags() & COT_LONGEST) != 0;
+ compl_get_longest = (get_cot_flags() & kOptCotFlagLongest) != 0;
compl_used_match = true;
}
@@ -2273,7 +2355,7 @@ bool ins_compl_prep(int c)
} else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
// Trigger the CompleteDone event to give scripts a chance to act
// upon the (possibly failed) completion.
- do_autocmd_completedone(c);
+ do_autocmd_completedone(c, ctrl_x_mode, NULL);
}
may_trigger_modechanged();
@@ -2293,18 +2375,18 @@ bool ins_compl_prep(int c)
/// "ptr" is the known leader text or NUL.
static void ins_compl_fixRedoBufForLeader(char *ptr_arg)
{
- int len;
+ int len = 0;
char *ptr = ptr_arg;
if (ptr == NULL) {
- if (compl_leader != NULL) {
- ptr = compl_leader;
+ if (compl_leader.data != NULL) {
+ ptr = compl_leader.data;
} else {
return; // nothing to do
}
}
- if (compl_orig_text != NULL) {
- char *p = compl_orig_text;
+ if (compl_orig_text.data != NULL) {
+ char *p = compl_orig_text.data;
for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {}
if (len > 0) {
len -= utf_head_off(p, p + len);
@@ -2312,8 +2394,6 @@ static void ins_compl_fixRedoBufForLeader(char *ptr_arg)
for (p += len; *p != NUL; MB_PTR_ADV(p)) {
AppendCharToRedobuff(K_BS);
}
- } else {
- len = 0;
}
AppendToRedobuffLit(ptr + len, -1);
}
@@ -2573,9 +2653,8 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
int flags = fast ? CP_FAST : 0;
char *(cptext[CPT_COUNT]);
char *user_abbr_hlname = NULL;
- int user_abbr_hlattr = -1;
char *user_kind_hlname = NULL;
- int user_kind_hlattr = -1;
+ int user_hl[2] = { -1, -1 };
typval_T user_data;
user_data.v_type = VAR_UNKNOWN;
@@ -2587,10 +2666,10 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
user_abbr_hlname = tv_dict_get_string(tv->vval.v_dict, "abbr_hlgroup", false);
- user_abbr_hlattr = get_user_highlight_attr(user_abbr_hlname);
+ user_hl[0] = get_user_highlight_attr(user_abbr_hlname);
user_kind_hlname = tv_dict_get_string(tv->vval.v_dict, "kind_hlgroup", false);
- user_kind_hlattr = get_user_highlight_attr(user_kind_hlname);
+ user_hl[1] = get_user_highlight_attr(user_kind_hlname);
tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data);
@@ -2613,8 +2692,7 @@ static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
return FAIL;
}
int status = ins_compl_add((char *)word, -1, NULL, cptext, true,
- &user_data, dir, flags, dup,
- user_abbr_hlattr, user_kind_hlattr);
+ &user_data, dir, flags, dup, user_hl);
if (status != OK) {
tv_clear(&user_data);
}
@@ -2682,9 +2760,9 @@ static void set_completion(colnr_T startcol, list_T *list)
{
int flags = CP_ORIGINAL_TEXT;
unsigned cur_cot_flags = get_cot_flags();
- bool compl_longest = (cur_cot_flags & COT_LONGEST) != 0;
- bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0;
- bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
+ bool compl_longest = (cur_cot_flags & kOptCotFlagLongest) != 0;
+ bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0;
+ bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0;
// If already doing completions stop it.
if (ctrl_x_mode_not_default()) {
@@ -2701,13 +2779,15 @@ static void set_completion(colnr_T startcol, list_T *list)
compl_col = startcol;
compl_length = curwin->w_cursor.col - startcol;
// compl_pattern doesn't need to be set
- compl_orig_text = xstrnsave(get_cursor_line_ptr() + compl_col, (size_t)compl_length);
+ compl_orig_text = cbuf_to_string(get_cursor_line_ptr() + compl_col,
+ (size_t)compl_length);
save_orig_extmarks();
if (p_ic) {
flags |= CP_ICASE;
}
- if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
- flags | CP_FAST, false, -1, -1) != OK) {
+ if (ins_compl_add(compl_orig_text.data, (int)compl_orig_text.size,
+ NULL, NULL, false, NULL, 0,
+ flags | CP_FAST, false, NULL) != OK) {
return;
}
@@ -2841,6 +2921,25 @@ static void ins_compl_update_sequence_numbers(void)
}
}
+/// Fill the dict of complete_info
+static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match)
+{
+ tv_dict_add_str(di, S_LEN("word"), match->cp_str.data);
+ tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]);
+ tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]);
+ tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]);
+ tv_dict_add_str(di, S_LEN("info"), match->cp_text[CPT_INFO]);
+ if (add_match) {
+ tv_dict_add_bool(di, S_LEN("match"), match->cp_in_match_array);
+ }
+ if (match->cp_user_data.v_type == VAR_UNKNOWN) {
+ // Add an empty string for backwards compatibility
+ tv_dict_add_str(di, S_LEN("user_data"), "");
+ } else {
+ tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
+ }
+}
+
/// Get complete information
static void get_complete_info(list_T *what_list, dict_T *retdict)
{
@@ -2848,12 +2947,13 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
#define CI_WHAT_PUM_VISIBLE 0x02
#define CI_WHAT_ITEMS 0x04
#define CI_WHAT_SELECTED 0x08
-#define CI_WHAT_INSERTED 0x10
+#define CI_WHAT_COMPLETED 0x10
+#define CI_WHAT_MATCHES 0x20
#define CI_WHAT_ALL 0xff
int what_flag;
if (what_list == NULL) {
- what_flag = CI_WHAT_ALL;
+ what_flag = CI_WHAT_ALL & ~(CI_WHAT_MATCHES|CI_WHAT_COMPLETED);
} else {
what_flag = 0;
for (listitem_T *item = tv_list_first(what_list)
@@ -2869,8 +2969,10 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
what_flag |= CI_WHAT_ITEMS;
} else if (strcmp(what, "selected") == 0) {
what_flag |= CI_WHAT_SELECTED;
- } else if (strcmp(what, "inserted") == 0) {
- what_flag |= CI_WHAT_INSERTED;
+ } else if (strcmp(what, "completed") == 0) {
+ what_flag |= CI_WHAT_COMPLETED;
+ } else if (strcmp(what, "matches") == 0) {
+ what_flag |= CI_WHAT_MATCHES;
}
}
}
@@ -2884,12 +2986,17 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
}
- if (ret == OK && (what_flag & CI_WHAT_ITEMS || what_flag & CI_WHAT_SELECTED)) {
+ if (ret == OK && (what_flag & (CI_WHAT_ITEMS|CI_WHAT_SELECTED
+ |CI_WHAT_MATCHES|CI_WHAT_COMPLETED))) {
list_T *li = NULL;
int selected_idx = -1;
- if (what_flag & CI_WHAT_ITEMS) {
+ bool has_items = what_flag & CI_WHAT_ITEMS;
+ bool has_matches = what_flag & CI_WHAT_MATCHES;
+ bool has_completed = what_flag & CI_WHAT_COMPLETED;
+ if (has_items || has_matches) {
li = tv_list_alloc(kListLenMayKnow);
- ret = tv_dict_add_list(retdict, S_LEN("items"), li);
+ const char *key = (has_matches && !has_items) ? "matches" : "items";
+ ret = tv_dict_add_list(retdict, key, strlen(key), li);
}
if (ret == OK && what_flag & CI_WHAT_SELECTED) {
if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) {
@@ -2901,20 +3008,10 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
compl_T *match = compl_first_match;
do {
if (!match_at_original_text(match)) {
- if (what_flag & CI_WHAT_ITEMS) {
+ if (has_items || (has_matches && match->cp_in_match_array)) {
dict_T *di = tv_dict_alloc();
tv_list_append_dict(li, di);
- tv_dict_add_str(di, S_LEN("word"), match->cp_str);
- tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]);
- tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]);
- tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]);
- tv_dict_add_str(di, S_LEN("info"), match->cp_text[CPT_INFO]);
- if (match->cp_user_data.v_type == VAR_UNKNOWN) {
- // Add an empty string for backwards compatibility
- tv_dict_add_str(di, S_LEN("user_data"), "");
- } else {
- tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
- }
+ fill_complete_info_dict(di, match, has_matches && has_items);
}
if (compl_curr_match != NULL
&& compl_curr_match->cp_number == match->cp_number) {
@@ -2933,11 +3030,14 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
tv_dict_add_nr(retdict, S_LEN("preview_bufnr"), wp->w_buffer->handle);
}
}
+ if (ret == OK && selected_idx != -1 && has_completed) {
+ dict_T *di = tv_dict_alloc();
+ fill_complete_info_dict(di, compl_curr_match, false);
+ ret = tv_dict_add_dict(retdict, S_LEN("completed"), di);
+ }
}
(void)ret;
- // TODO(vim):
- // if (ret == OK && (what_flag & CI_WHAT_INSERTED))
}
/// "complete_info()" function
@@ -3040,6 +3140,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
}
if (!shortmess(SHM_COMPLETIONSCAN)) {
msg_hist_off = true; // reset in msg_trunc()
+ msg_ext_set_kind("completion");
vim_snprintf(IObuff, IOSIZE, _("Scanning: %s"),
st->ins_buf->b_fname == NULL
? buf_spname(st->ins_buf)
@@ -3072,6 +3173,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
} else if (*st->e_cpt == ']' || *st->e_cpt == 't') {
compl_type = CTRL_X_TAGS;
if (!shortmess(SHM_COMPLETIONSCAN)) {
+ msg_ext_set_kind("completion");
msg_hist_off = true; // reset in msg_trunc()
vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags."));
msg_trunc(IObuff, true, HLF_R);
@@ -3096,8 +3198,8 @@ done:
/// included files.
static void get_next_include_file_completion(int compl_type)
{
- find_pattern_in_path(compl_pattern, compl_direction,
- compl_patternlen, false, false,
+ find_pattern_in_path(compl_pattern.data, compl_direction,
+ compl_pattern.size, false, false,
((compl_type == CTRL_X_PATH_DEFINES
&& !(compl_cont_status & CONT_SOL))
? FIND_DEFINE : FIND_ANY),
@@ -3109,14 +3211,14 @@ static void get_next_include_file_completion(int compl_type)
static void get_next_dict_tsr_completion(int compl_type, char *dict, int dict_f)
{
if (thesaurus_func_complete(compl_type)) {
- expand_by_function(compl_type, compl_pattern);
+ expand_by_function(compl_type, compl_pattern.data);
} else {
ins_compl_dictionaries(dict != NULL
? dict
: (compl_type == CTRL_X_THESAURUS
? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
: (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)),
- compl_pattern,
+ compl_pattern.data,
dict != NULL ? dict_f : 0,
compl_type == CTRL_X_THESAURUS);
}
@@ -3127,14 +3229,14 @@ static void get_next_tag_completion(void)
{
// set p_ic according to p_ic, p_scs and pat for find_tags().
const int save_p_ic = p_ic;
- p_ic = ignorecase(compl_pattern);
+ p_ic = ignorecase(compl_pattern.data);
// Find up to TAG_MANY matches. Avoids that an enormous number
// of matches is found when compl_pattern is empty
g_tag_at_cursor = true;
char **matches;
int num_matches;
- if (find_tags(compl_pattern, &num_matches, &matches,
+ if (find_tags(compl_pattern.data, &num_matches, &matches,
TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
| (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0),
TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) {
@@ -3149,13 +3251,13 @@ static void get_next_filename_completion(void)
{
char **matches;
int num_matches;
- if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
+ if (expand_wildcards(1, &compl_pattern.data, &num_matches, &matches,
EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) {
return;
}
// May change home directory back to "~".
- tilde_replace(compl_pattern, num_matches, matches);
+ tilde_replace(compl_pattern.data, num_matches, matches);
#ifdef BACKSLASH_IN_FILENAME
if (curbuf->b_p_csl[0] != NUL) {
for (int i = 0; i < num_matches; i++) {
@@ -3179,8 +3281,8 @@ static void get_next_cmdline_completion(void)
{
char **matches;
int num_matches;
- if (expand_cmdline(&compl_xp, compl_pattern,
- (int)compl_patternlen, &num_matches, &matches) == EXPAND_OK) {
+ if (expand_cmdline(&compl_xp, compl_pattern.data,
+ (int)compl_pattern.size, &num_matches, &matches) == EXPAND_OK) {
ins_compl_add_matches(num_matches, matches, false);
}
}
@@ -3189,7 +3291,7 @@ static void get_next_cmdline_completion(void)
static void get_next_spell_completion(linenr_T lnum)
{
char **matches;
- int num_matches = expand_spelling(lnum, compl_pattern, &matches);
+ int num_matches = expand_spelling(lnum, compl_pattern.data, &matches);
if (num_matches > 0) {
ins_compl_add_matches(num_matches, matches, p_ic);
} else {
@@ -3208,22 +3310,24 @@ static char *ins_compl_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_po
{
*match_len = 0;
char *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum) + cur_match_pos->col;
- int len;
+ int len = ml_get_buf_len(ins_buf, cur_match_pos->lnum) - cur_match_pos->col;
if (ctrl_x_mode_line_or_eval()) {
if (compl_status_adding()) {
if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) {
return NULL;
}
ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1);
+ len = ml_get_buf_len(ins_buf, cur_match_pos->lnum + 1);
if (!p_paste) {
- ptr = skipwhite(ptr);
+ char *tmp_ptr = ptr;
+ ptr = skipwhite(tmp_ptr);
+ len -= (int)(ptr - tmp_ptr);
}
}
- len = (int)strlen(ptr);
} else {
char *tmp_ptr = ptr;
- if (compl_status_adding() && compl_length <= (int)strlen(tmp_ptr)) {
+ if (compl_status_adding() && compl_length <= len) {
tmp_ptr += compl_length;
// Skip if already inside a word.
if (vim_iswordp(tmp_ptr)) {
@@ -3319,10 +3423,11 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
// has added a word that was at the beginning of the line.
if (ctrl_x_mode_line_or_eval() || (compl_cont_status & CONT_SOL)) {
found_new_match = search_for_exact_line(st->ins_buf, st->cur_match_pos,
- compl_direction, compl_pattern);
+ compl_direction, compl_pattern.data);
} else {
found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
- NULL, compl_direction, compl_pattern, compl_patternlen,
+ NULL, compl_direction, compl_pattern.data,
+ compl_pattern.size,
1, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
}
msg_silent--;
@@ -3368,7 +3473,8 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
int len;
char *ptr = ins_compl_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
&len, &cont_s_ipos);
- if (ptr == NULL) {
+ if (ptr == NULL
+ || (ins_compl_has_preinsert() && strcmp(ptr, compl_pattern.data) == 0)) {
continue;
}
if (ins_compl_add_infercase(ptr, len, p_ic,
@@ -3419,7 +3525,7 @@ static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_
case CTRL_X_FUNCTION:
case CTRL_X_OMNI:
- expand_by_function(type, compl_pattern);
+ expand_by_function(type, compl_pattern.data);
break;
case CTRL_X_SPELL:
@@ -3450,9 +3556,9 @@ static void get_next_bufname_token(void)
FOR_ALL_BUFFERS(b) {
if (b->b_p_bl && b->b_sfname != NULL) {
char *tail = path_tail(b->b_sfname);
- if (strncmp(tail, compl_orig_text, strlen(compl_orig_text)) == 0) {
+ if (strncmp(tail, compl_orig_text.data, compl_orig_text.size) == 0) {
ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0,
- p_ic ? CP_ICASE : 0, false, -1, -1);
+ p_ic ? CP_ICASE : 0, false, NULL);
}
}
}
@@ -3518,7 +3624,7 @@ static int ins_compl_get_exp(pos_T *ini)
// If complete() was called then compl_pattern has been reset.
// The following won't work then, bail out.
- if (compl_pattern == NULL) {
+ if (compl_pattern.data == NULL) {
break;
}
@@ -3586,7 +3692,7 @@ static int ins_compl_get_exp(pos_T *ini)
static void ins_compl_update_shown_match(void)
{
while (!ins_compl_equal(compl_shown_match,
- compl_leader, strlen(compl_leader))
+ compl_leader.data, compl_leader.size)
&& compl_shown_match->cp_next != NULL
&& !is_first_match(compl_shown_match->cp_next)) {
compl_shown_match = compl_shown_match->cp_next;
@@ -3595,10 +3701,10 @@ static void ins_compl_update_shown_match(void)
// If we didn't find it searching forward, and compl_shows_dir is
// backward, find the last match.
if (compl_shows_dir_backward()
- && !ins_compl_equal(compl_shown_match, compl_leader, strlen(compl_leader))
+ && !ins_compl_equal(compl_shown_match, compl_leader.data, compl_leader.size)
&& (compl_shown_match->cp_next == NULL
|| is_first_match(compl_shown_match->cp_next))) {
- while (!ins_compl_equal(compl_shown_match, compl_leader, strlen(compl_leader))
+ while (!ins_compl_equal(compl_shown_match, compl_leader.data, compl_leader.size)
&& compl_shown_match->cp_prev != NULL
&& !is_first_match(compl_shown_match->cp_prev)) {
compl_shown_match = compl_shown_match->cp_prev;
@@ -3607,16 +3713,36 @@ static void ins_compl_update_shown_match(void)
}
/// Delete the old text being completed.
-void ins_compl_delete(void)
+void ins_compl_delete(bool new_leader)
{
+ // Avoid deleting text that will be reinserted when changing leader. This
+ // allows marks present on the original text to shrink/grow appropriately.
+ int orig_col = 0;
+ if (new_leader) {
+ char *orig = compl_orig_text.data;
+ char *leader = ins_compl_leader();
+ while (*orig != NUL && utf_ptr2char(orig) == utf_ptr2char(leader)) {
+ leader += utf_ptr2len(leader);
+ orig += utf_ptr2len(orig);
+ }
+ orig_col = (int)(orig - compl_orig_text.data);
+ }
+
// In insert mode: Delete the typed part.
// In replace mode: Put the old characters back, if any.
- int col = compl_col + (compl_status_adding() ? compl_length : 0);
+ int col = compl_col + (compl_status_adding() ? compl_length : orig_col);
+ bool has_preinsert = ins_compl_preinsert_effect();
+ if (has_preinsert) {
+ col += (int)ins_compl_leader_len();
+ curwin->w_cursor.col = compl_ins_end_col;
+ }
+
if ((int)curwin->w_cursor.col > col) {
if (stop_arrow() == FAIL) {
return;
}
backspace_until_column(col);
+ compl_ins_end_col = curwin->w_cursor.col;
}
// TODO(vim): is this sufficient for redrawing? Redrawing everything
@@ -3628,15 +3754,25 @@ void ins_compl_delete(void)
/// Insert the new text being completed.
/// "in_compl_func" is true when called from complete_check().
-void ins_compl_insert(bool in_compl_func)
+/// "move_cursor" is used when 'completeopt' includes "preinsert" and when true
+/// cursor needs to move back from the inserted text to the compl_leader.
+void ins_compl_insert(bool in_compl_func, bool move_cursor)
{
int compl_len = get_compl_len();
+ bool preinsert = ins_compl_has_preinsert();
+ char *cp_str = compl_shown_match->cp_str.data;
+ size_t cp_str_len = compl_shown_match->cp_str.size;
+ size_t leader_len = ins_compl_leader_len();
+
// Make sure we don't go over the end of the string, this can happen with
// illegal bytes.
- if (compl_len < (int)strlen(compl_shown_match->cp_str)) {
- ins_bytes(compl_shown_match->cp_str + compl_len);
+ if (compl_len < (int)cp_str_len) {
+ ins_compl_insert_bytes(cp_str + compl_len, -1);
+ if (preinsert && move_cursor) {
+ curwin->w_cursor.col -= (colnr_T)(cp_str_len - leader_len);
+ }
}
- compl_used_match = !match_at_original_text(compl_shown_match);
+ compl_used_match = !(match_at_original_text(compl_shown_match) || preinsert);
dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
set_vim_var_dict(VV_COMPLETED_ITEM, dict);
@@ -3704,7 +3840,7 @@ static compl_T *find_comp_when_fuzzy(void)
comp = compl_first_match;
do {
if (comp->cp_score == score
- && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) {
+ && (str == comp->cp_str.data || str == comp->cp_text[CPT_ABBR])) {
return comp;
}
comp = comp->cp_next;
@@ -3731,8 +3867,8 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
bool found_end = false;
compl_T *found_compl = NULL;
unsigned cur_cot_flags = get_cot_flags();
- bool compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0;
- bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
+ bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
while (--todo >= 0) {
if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) {
@@ -3787,9 +3923,9 @@ static int find_next_completion_match(bool allow_get_expansion, int todo, bool a
found_end = false;
}
if (!match_at_original_text(compl_shown_match)
- && compl_leader != NULL
+ && compl_leader.data != NULL
&& !ins_compl_equal(compl_shown_match,
- compl_leader, strlen(compl_leader))
+ compl_leader.data, compl_leader.size)
&& !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) {
todo++;
} else {
@@ -3836,8 +3972,9 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
const bool started = compl_started;
buf_T *const orig_curbuf = curbuf;
unsigned cur_cot_flags = get_cot_flags();
- bool compl_no_insert = (cur_cot_flags & COT_NOINSERT) != 0;
- bool compl_fuzzy_match = (cur_cot_flags & COT_FUZZY) != 0;
+ bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0;
+ bool compl_fuzzy_match = (cur_cot_flags & kOptCotFlagFuzzy) != 0;
+ bool compl_preinsert = ins_compl_has_preinsert();
// When user complete function return -1 for findstart which is next
// time of 'always', compl_shown_match become NULL.
@@ -3845,7 +3982,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
return -1;
}
- if (compl_leader != NULL
+ if (compl_leader.data != NULL
&& !match_at_original_text(compl_shown_match)
&& !compl_fuzzy_match) {
// Update "compl_shown_match" to the actually shown match
@@ -3855,7 +3992,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
if (allow_get_expansion && insert_match
&& (!compl_get_longest || compl_used_match)) {
// Delete old text to be replaced
- ins_compl_delete();
+ ins_compl_delete(false);
}
// When finding the longest common text we stick at the original text,
@@ -3882,17 +4019,18 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
}
// Insert the text of the new completion, or the compl_leader.
- if (compl_no_insert && !started) {
- ins_bytes(compl_orig_text + get_compl_len());
+ if (compl_no_insert && !started && !compl_preinsert) {
+ ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1);
compl_used_match = false;
restore_orig_extmarks();
} else if (insert_match) {
if (!compl_get_longest || compl_used_match) {
- ins_compl_insert(in_compl_func);
+ ins_compl_insert(in_compl_func, true);
} else {
- ins_bytes(compl_leader + get_compl_len());
+ assert(compl_leader.data != NULL);
+ ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1);
}
- if (!strcmp(compl_curr_match->cp_str, compl_orig_text)) {
+ if (strequal(compl_curr_match->cp_str.data, compl_orig_text.data)) {
restore_orig_extmarks();
}
} else {
@@ -3908,7 +4046,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
// Delete old text to be replaced, since we're still searching and
// don't want to match ourselves!
- ins_compl_delete();
+ ins_compl_delete(false);
}
// Enter will select a match when the match wasn't inserted and the popup
@@ -3976,7 +4114,7 @@ void ins_compl_check_keys(int frequency, bool in_compl_func)
}
}
}
- if (compl_pending != 0 && !got_int && !(cot_flags & COT_NOINSERT)) {
+ if (compl_pending != 0 && !got_int && !(cot_flags & kOptCotFlagNoinsert)) {
int todo = compl_pending > 0 ? compl_pending : -compl_pending;
compl_pending = 0;
@@ -4056,8 +4194,7 @@ static bool ins_compl_use_match(int c)
/// Get the pattern, column and length for normal completion (CTRL-N CTRL-P
/// completion)
-/// Sets the global variables: compl_col, compl_length, compl_pattern and
-/// compl_patternlen.
+/// 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 *line, int startcol, colnr_T curs_col)
{
@@ -4068,29 +4205,32 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
compl_length = curs_col - startcol;
}
if (p_ic) {
- compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
+ compl_pattern = cstr_as_string(str_foldcase(line + compl_col,
+ compl_length, NULL, 0));
} else {
- compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
+ compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length);
}
} else if (compl_status_adding()) {
char *prefix = "\\<";
size_t prefixlen = STRLEN_LITERAL("\\<");
- // we need up to 2 extra chars for the prefix
- compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
- compl_length) + prefixlen);
if (!vim_iswordp(line + compl_col)
|| (compl_col > 0
&& (vim_iswordp(mb_prevptr(line, line + compl_col))))) {
prefix = "";
prefixlen = 0;
}
- STRCPY(compl_pattern, prefix);
- quote_meta(compl_pattern + prefixlen, line + compl_col, compl_length);
+
+ // we need up to 2 extra chars for the prefix
+ size_t n = quote_meta(NULL, line + compl_col, compl_length) + prefixlen;
+ compl_pattern.data = xmalloc(n);
+ STRCPY(compl_pattern.data, prefix);
+ quote_meta(compl_pattern.data + prefixlen, line + compl_col, compl_length);
+ compl_pattern.size = n - 1;
} else if (--startcol < 0
|| !vim_iswordp(mb_prevptr(line, line + startcol + 1))) {
// Match any word of at least two chars
- compl_pattern = xstrnsave(S_LEN("\\<\\k\\k"));
+ compl_pattern = cbuf_to_string(S_LEN("\\<\\k\\k"));
compl_col += curs_col;
compl_length = 0;
} else {
@@ -4111,19 +4251,20 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col)
// Only match word with at least two chars -- webb
// there's no need to call quote_meta,
// xmalloc(7) is enough -- Acevedo
- compl_pattern = xmalloc(7);
- STRCPY(compl_pattern, "\\<");
- quote_meta(compl_pattern + 2, line + compl_col, 1);
- strcat(compl_pattern, "\\k");
+ compl_pattern.data = xmalloc(7);
+ STRCPY(compl_pattern.data, "\\<");
+ quote_meta(compl_pattern.data + 2, line + compl_col, 1);
+ strcat(compl_pattern.data, "\\k");
+ compl_pattern.size = strlen(compl_pattern.data);
} else {
- compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2);
- STRCPY(compl_pattern, "\\<");
- quote_meta(compl_pattern + 2, line + compl_col, compl_length);
+ size_t n = quote_meta(NULL, line + compl_col, compl_length) + 2;
+ compl_pattern.data = xmalloc(n);
+ STRCPY(compl_pattern.data, "\\<");
+ quote_meta(compl_pattern.data + 2, line + compl_col, compl_length);
+ compl_pattern.size = n - 1;
}
}
- compl_patternlen = strlen(compl_pattern);
-
return OK;
}
@@ -4138,13 +4279,12 @@ static int get_wholeline_compl_info(char *line, colnr_T curs_col)
compl_length = 0;
}
if (p_ic) {
- compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
+ compl_pattern = cstr_as_string(str_foldcase(line + compl_col,
+ compl_length, NULL, 0));
} else {
- compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
+ compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length);
}
- compl_patternlen = strlen(compl_pattern);
-
return OK;
}
@@ -4169,8 +4309,8 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col)
compl_col += startcol;
compl_length = (int)curs_col - startcol;
- compl_pattern = addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES);
- compl_patternlen = strlen(compl_pattern);
+ compl_pattern = cstr_as_string(addstar(line + compl_col,
+ (size_t)compl_length, EXPAND_FILES));
return OK;
}
@@ -4179,9 +4319,9 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col)
/// Sets the global variables: compl_col, compl_length and compl_pattern.
static int get_cmdline_compl_info(char *line, colnr_T curs_col)
{
- compl_pattern = xstrnsave(line, (size_t)curs_col);
- compl_patternlen = (size_t)curs_col;
- set_cmd_context(&compl_xp, compl_pattern, (int)compl_patternlen, curs_col, false);
+ compl_pattern = cbuf_to_string(line, (size_t)curs_col);
+ set_cmd_context(&compl_xp, compl_pattern.data,
+ (int)compl_pattern.size, curs_col, false);
if (compl_xp.xp_context == EXPAND_LUA) {
nlua_expand_pat(&compl_xp);
}
@@ -4191,7 +4331,7 @@ static int get_cmdline_compl_info(char *line, colnr_T curs_col)
// "pattern not found" message.
compl_col = curs_col;
} else {
- compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
+ compl_col = (int)(compl_xp.xp_pattern - compl_pattern.data);
}
compl_length = curs_col - compl_col;
@@ -4269,8 +4409,7 @@ static int get_userdefined_compl_info(colnr_T curs_col)
// it may have become invalid.
char *line = ml_get(curwin->w_cursor.lnum);
compl_length = curs_col - compl_col;
- compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
- compl_patternlen = (size_t)compl_length;
+ compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length);
return OK;
}
@@ -4295,8 +4434,7 @@ static int get_spell_compl_info(int startcol, colnr_T curs_col)
}
// Need to obtain "line" again, it may have become invalid.
char *line = ml_get(curwin->w_cursor.lnum);
- compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length);
- compl_patternlen = (size_t)compl_length;
+ compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length);
return OK;
}
@@ -4481,19 +4619,19 @@ static int ins_compl_start(void)
ins_compl_fixRedoBufForLeader(NULL);
// Always add completion for the original text.
- xfree(compl_orig_text);
+ API_CLEAR_STRING(compl_orig_text);
kv_destroy(compl_orig_extmarks);
- compl_orig_text = xstrnsave(line + compl_col, (size_t)compl_length);
+ compl_orig_text = cbuf_to_string(line + compl_col, (size_t)compl_length);
save_orig_extmarks();
int flags = CP_ORIGINAL_TEXT;
if (p_ic) {
flags |= CP_ICASE;
}
- if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0,
- flags, false, -1, -1) != OK) {
- XFREE_CLEAR(compl_pattern);
- compl_patternlen = 0;
- XFREE_CLEAR(compl_orig_text);
+ if (ins_compl_add(compl_orig_text.data, (int)compl_orig_text.size,
+ NULL, NULL, false, NULL, 0,
+ flags, false, NULL) != OK) {
+ API_CLEAR_STRING(compl_pattern);
+ API_CLEAR_STRING(compl_orig_text);
kv_destroy(compl_orig_extmarks);
return FAIL;
}
@@ -4567,6 +4705,7 @@ static void ins_compl_show_statusmsg(void)
if (edit_submode_extra != NULL) {
if (!p_smd) {
msg_hist_off = true;
+ msg_ext_set_kind("completion");
msg(edit_submode_extra, (edit_submode_highl < HLF_COUNT
? (int)edit_submode_highl + 1 : 0));
msg_hist_off = false;
@@ -4726,7 +4865,7 @@ static unsigned quote_meta(char *dest, char *src, int len)
#if defined(EXITFREE)
void free_insexpand_stuff(void)
{
- XFREE_CLEAR(compl_orig_text);
+ API_CLEAR_STRING(compl_orig_text);
kv_destroy(compl_orig_extmarks);
callback_free(&cfu_cb);
callback_free(&ofu_cb);