aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/insexpand.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-30 20:35:25 +0000
commit1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch)
treecd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/insexpand.c
parenteaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-aucmd_textputpost.tar.gz
rneovim-aucmd_textputpost.tar.bz2
rneovim-aucmd_textputpost.zip
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/insexpand.c')
-rw-r--r--src/nvim/insexpand.c416
1 files changed, 227 insertions, 189 deletions
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 6de3b0a9d0..12543a2d42 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -1,6 +1,3 @@
-// This is an open source non-commercial project. Dear PVS-Studio, please check
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-
// insexpand.c: functions for Insert mode completion
#include <assert.h>
@@ -12,7 +9,7 @@
#include <stdlib.h>
#include <string.h>
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
@@ -23,23 +20,21 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/ex_cmds_defs.h"
-#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
+#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
-#include "nvim/highlight_defs.h"
+#include "nvim/highlight.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/insexpand.h"
#include "nvim/keycodes.h"
-#include "nvim/macros.h"
+#include "nvim/macros_defs.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -47,24 +42,26 @@
#include "nvim/message.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/option_defs.h"
+#include "nvim/option_vars.h"
#include "nvim/os/fs.h"
#include "nvim/os/input.h"
#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/popupmenu.h"
-#include "nvim/pos.h"
+#include "nvim/pos_defs.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/tag.h"
#include "nvim/textformat.h"
-#include "nvim/types.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.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[]
@@ -91,6 +88,7 @@ enum {
CTRL_X_LOCAL_MSG = 15, ///< only used in "ctrl_x_msgs"
CTRL_X_EVAL = 16, ///< for builtin function complete()
CTRL_X_CMDLINE_CTRL_X = 17, ///< CTRL-X typed in CTRL_X_CMDLINE
+ CTRL_X_BUFNAMES = 18,
};
#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
@@ -162,7 +160,8 @@ struct compl_S {
/// state information used for getting the next set of insert completion
/// matches.
typedef struct {
- char *e_cpt; ///< current entry in 'complete'
+ char *e_cpt_copy; ///< copy of 'complete'
+ char *e_cpt; ///< current entry in "e_cpt_copy"
buf_T *ins_buf; ///< buffer being scanned
pos_T *cur_match_pos; ///< current match position
pos_T prev_match_pos; ///< previous match position
@@ -188,8 +187,8 @@ typedef enum {
CP_FAST = 32, ///< use fast_breakcheck instead of os_breakcheck
} cp_flags_T;
-static char e_hitend[] = N_("Hit end of paragraph");
-static char e_compldel[] = N_("E840: Completion function deleted text");
+static const char e_hitend[] = N_("Hit end of paragraph");
+static const char e_compldel[] = N_("E840: Completion function deleted text");
// All the current matches are stored in a list.
// "compl_first_match" points to the start of the list.
@@ -466,14 +465,13 @@ bool check_compl_option(bool dict_opt)
&& *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));
+ msg((dict_opt ? _("'dictionary' option is empty") : _("'thesaurus' option is empty")),
+ HL_ATTR(HLF_E));
if (emsg_silent == 0 && !in_assert_fails) {
vim_beep(BO_COMPL);
setcursor();
ui_flush();
- os_delay(2004L, false);
+ os_delay(2004, false);
}
return false;
}
@@ -536,6 +534,8 @@ bool vim_is_ctrl_x_key(int c)
return c == Ctrl_S || c == Ctrl_P || c == Ctrl_N;
case CTRL_X_EVAL:
return (c == Ctrl_P || c == Ctrl_N);
+ case CTRL_X_BUFNAMES:
+ return (c == Ctrl_P || c == Ctrl_N);
}
internal_error("vim_is_ctrl_x_key()");
return false;
@@ -909,8 +909,6 @@ static bool ins_compl_equal(compl_T *match, char *str, size_t len)
/// Reduce the longest common string for match "match".
static void ins_compl_longest_match(compl_T *match)
{
- char *p, *s;
- int c1, c2;
int had_match;
if (compl_leader == NULL) {
@@ -933,11 +931,11 @@ static void ins_compl_longest_match(compl_T *match)
}
// Reduce the text if this match differs from compl_leader.
- p = compl_leader;
- s = match->cp_str;
+ char *p = compl_leader;
+ char *s = match->cp_str;
while (*p != NUL) {
- c1 = utf_ptr2char(p);
- c2 = utf_ptr2char(s);
+ int c1 = utf_ptr2char(p);
+ int c2 = utf_ptr2char(s);
if ((match->cp_flags & CP_ICASE)
? (mb_tolower(c1) != mb_tolower(c2))
@@ -1068,14 +1066,14 @@ static bool pum_enough_matches(void)
{
// Don't display the popup menu if there are no matches or there is only
// one (ignoring the original text).
- compl_T *compl = compl_first_match;
+ compl_T *comp = compl_first_match;
int i = 0;
do {
- if (compl == NULL || (!match_at_original_text(compl) && ++i == 2)) {
+ if (comp == NULL || (!match_at_original_text(comp) && ++i == 2)) {
break;
}
- compl = compl->cp_next;
- } while (!is_first_match(compl));
+ comp = comp->cp_next;
+ } while (!is_first_match(comp));
if (strstr(p_cot, "menuone") != NULL) {
return i >= 1;
@@ -1139,7 +1137,7 @@ static int ins_compl_build_pum(void)
{
// Need to build the popup menu list.
compl_match_arraysize = 0;
- compl_T *compl = compl_first_match;
+ compl_T *comp = compl_first_match;
// If it's user complete function and refresh_always,
// do not use "compl_leader" as prefix filter.
@@ -1150,13 +1148,13 @@ static int ins_compl_build_pum(void)
const int lead_len = compl_leader != NULL ? (int)strlen(compl_leader) : 0;
do {
- if (!match_at_original_text(compl)
+ if (!match_at_original_text(comp)
&& (compl_leader == NULL
- || ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
+ || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) {
compl_match_arraysize++;
}
- compl = compl->cp_next;
- } while (compl != NULL && !is_first_match(compl));
+ comp = comp->cp_next;
+ } while (comp != NULL && !is_first_match(comp));
if (compl_match_arraysize == 0) {
return -1;
@@ -1173,46 +1171,46 @@ static int ins_compl_build_pum(void)
bool did_find_shown_match = false;
int cur = -1;
int i = 0;
- compl = compl_first_match;
+ comp = compl_first_match;
do {
- if (!match_at_original_text(compl)
+ if (!match_at_original_text(comp)
&& (compl_leader == NULL
- || ins_compl_equal(compl, compl_leader, (size_t)lead_len))) {
+ || ins_compl_equal(comp, compl_leader, (size_t)lead_len))) {
if (!shown_match_ok) {
- if (compl == compl_shown_match || did_find_shown_match) {
+ 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.
- compl_shown_match = compl;
+ compl_shown_match = comp;
did_find_shown_match = true;
shown_match_ok = true;
} else {
// Remember this displayed match for when the
// shown match is just below it.
- shown_compl = compl;
+ shown_compl = comp;
}
cur = i;
}
- if (compl->cp_text[CPT_ABBR] != NULL) {
- compl_match_array[i].pum_text = compl->cp_text[CPT_ABBR];
+ 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 = compl->cp_str;
+ compl_match_array[i].pum_text = comp->cp_str;
}
- compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
- compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
- if (compl->cp_text[CPT_MENU] != NULL) {
- compl_match_array[i++].pum_extra = compl->cp_text[CPT_MENU];
+ compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND];
+ compl_match_array[i].pum_info = comp->cp_text[CPT_INFO];
+ 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 = compl->cp_fname;
+ compl_match_array[i++].pum_extra = comp->cp_fname;
}
}
- if (compl == compl_shown_match) {
+ if (comp == compl_shown_match) {
did_find_shown_match = true;
// When the original text is the shown match don't set
// compl_shown_match.
- if (match_at_original_text(compl)) {
+ if (match_at_original_text(comp)) {
shown_match_ok = true;
}
@@ -1223,8 +1221,8 @@ static int ins_compl_build_pum(void)
shown_match_ok = true;
}
}
- compl = compl->cp_next;
- } while (compl != NULL && !is_first_match(compl));
+ comp = comp->cp_next;
+ } while (comp != NULL && !is_first_match(comp));
if (!shown_match_ok) { // no displayed match at all
cur = -1;
@@ -1241,9 +1239,6 @@ void ins_compl_show_pum(void)
return;
}
- // Dirty hard-coded hack: remove any matchparen highlighting.
- do_cmdline_cmd("if exists('g:loaded_matchparen')|3match none|endif");
-
// Update the screen before drawing the popup menu over it.
update_screen();
@@ -1298,11 +1293,9 @@ static void ins_compl_dictionaries(char *dict_start, char *pat, int flags, int t
{
char *dict = dict_start;
char *ptr;
- char *buf;
regmatch_T regmatch;
char **files;
int count;
- int save_p_scs;
Direction dir = compl_direction;
if (*dict == NUL) {
@@ -1315,11 +1308,11 @@ static void ins_compl_dictionaries(char *dict_start, char *pat, int flags, int t
}
}
- buf = xmalloc(LSIZE);
+ char *buf = xmalloc(LSIZE);
regmatch.regprog = NULL; // so that we can goto theend
// If 'infercase' is set, don't use 'smartcase' here
- save_p_scs = p_scs;
+ int save_p_scs = p_scs;
if (curbuf->b_p_inf) {
p_scs = false;
}
@@ -1415,7 +1408,7 @@ static int thesaurus_add_words_in_line(char *fname, char **buf_arg, int dir, con
// different classes, only separate words
// with single-byte non-word characters.
while (*ptr != NUL) {
- const int l = utfc_ptr2len((const char *)ptr);
+ const int l = utfc_ptr2len(ptr);
if (l < 2 && !vim_iswordc((uint8_t)(*ptr))) {
break;
@@ -1443,18 +1436,13 @@ static void ins_compl_files(int count, char **files, int thesaurus, int flags, r
char *buf, Direction *dir)
FUNC_ATTR_NONNULL_ARG(2, 7)
{
- char *ptr;
- int i;
- FILE *fp;
- int add_r;
-
- for (i = 0; i < count && !got_int && !compl_interrupted; i++) {
- fp = os_fopen(files[i], "r"); // open dictionary file
+ for (int i = 0; i < count && !got_int && !compl_interrupted; i++) {
+ 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_attr()
+ msg_hist_off = true; // reset in msg_trunc()
vim_snprintf(IObuff, IOSIZE,
_("Scanning dictionary: %s"), files[i]);
- (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
+ (void)msg_trunc(IObuff, true, HL_ATTR(HLF_R));
}
if (fp == NULL) {
@@ -1464,7 +1452,7 @@ static void ins_compl_files(int count, char **files, int thesaurus, int flags, r
// Read dictionary file line by line.
// Check each line for a match.
while (!got_int && !compl_interrupted && !vim_fgets(buf, LSIZE, fp)) {
- ptr = buf;
+ char *ptr = buf;
while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf))) {
ptr = regmatch->startp[0];
if (ctrl_x_mode_line_or_eval()) {
@@ -1472,9 +1460,9 @@ static void ins_compl_files(int count, char **files, int thesaurus, int flags, r
} else {
ptr = find_word_end(ptr);
}
- add_r = ins_compl_add_infercase(regmatch->startp[0],
- (int)(ptr - regmatch->startp[0]),
- p_ic, files[i], *dir, false);
+ int add_r = ins_compl_add_infercase(regmatch->startp[0],
+ (int)(ptr - regmatch->startp[0]),
+ p_ic, files[i], *dir, false);
if (thesaurus) {
// For a thesaurus, add all the words in the line
ptr = buf;
@@ -1532,9 +1520,7 @@ char *find_word_end(char *ptr)
/// @return a pointer to just after the line.
static char *find_line_end(char *ptr)
{
- char *s;
-
- s = ptr + strlen(ptr);
+ char *s = ptr + strlen(ptr);
while (s > ptr && (s[-1] == CAR || s[-1] == NL)) {
s--;
}
@@ -1544,8 +1530,6 @@ static char *find_line_end(char *ptr)
/// Free the list of completions
static void ins_compl_free(void)
{
- compl_T *match;
-
XFREE_CLEAR(compl_pattern);
XFREE_CLEAR(compl_leader);
@@ -1558,7 +1542,7 @@ static void ins_compl_free(void)
compl_curr_match = compl_first_match;
do {
- match = compl_curr_match;
+ compl_T *match = compl_curr_match;
compl_curr_match = compl_curr_match->cp_next;
xfree(match->cp_str);
// several entries may use the same fname, free it just once.
@@ -1749,9 +1733,9 @@ void ins_compl_addleader(int c)
return;
}
if ((cc = utf_char2len(c)) > 1) {
- char buf[MB_MAXBYTES + 1];
+ char buf[MB_MAXCHAR + 1];
- utf_char2bytes(c, (char *)buf);
+ utf_char2bytes(c, buf);
buf[cc] = NUL;
ins_char_bytes(buf, (size_t)cc);
} else {
@@ -1805,12 +1789,9 @@ static void ins_compl_set_original_text(char *str)
/// matches.
void ins_compl_addfrommatch(void)
{
- char *p;
int len = (int)curwin->w_cursor.col - (int)compl_col;
- int c;
- compl_T *cp;
assert(compl_shown_match != NULL);
- p = compl_shown_match->cp_str;
+ char *p = compl_shown_match->cp_str;
if ((int)strlen(p) <= len) { // the match is too short
// When still at the original match use the first entry that matches
// the leader.
@@ -1819,7 +1800,7 @@ void ins_compl_addfrommatch(void)
}
p = NULL;
- for (cp = compl_shown_match->cp_next; cp != NULL
+ 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))) {
@@ -1832,7 +1813,7 @@ void ins_compl_addfrommatch(void)
}
}
p += len;
- c = utf_ptr2char(p);
+ int c = utf_ptr2char(p);
ins_compl_addleader(c);
}
@@ -2096,10 +2077,10 @@ bool ins_compl_prep(int c)
edit_submode_extra = NULL;
}
- // Ignore end of Select mode mapping and mouse scroll buttons.
+ // Ignore end of Select mode mapping and mouse scroll/movement.
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
- || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
- || c == K_COMMAND || c == K_LUA) {
+ || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_MOUSEMOVE
+ || c == K_EVENT || c == K_COMMAND || c == K_LUA) {
return retval;
}
@@ -2184,7 +2165,6 @@ bool ins_compl_prep(int c)
static void ins_compl_fixRedoBufForLeader(char *ptr_arg)
{
int len;
- char *p;
char *ptr = ptr_arg;
if (ptr == NULL) {
@@ -2195,7 +2175,7 @@ static void ins_compl_fixRedoBufForLeader(char *ptr_arg)
}
}
if (compl_orig_text != NULL) {
- p = compl_orig_text;
+ char *p = compl_orig_text;
for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {}
if (len > 0) {
len -= utf_head_off(p, p + len);
@@ -2220,7 +2200,8 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
static win_T *wp = NULL;
if (flag == 'w') { // just windows
- if (buf == curbuf || wp == NULL) { // first call for this flag/expansion
+ if (buf == curbuf || !win_valid(wp)) {
+ // first call for this flag/expansion or window was closed
wp = curwin;
}
assert(wp);
@@ -2258,14 +2239,14 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb)
/// Invoked when the 'completefunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-void set_completefunc_option(char **errmsg)
+const char *did_set_completefunc(optset_T *args FUNC_ATTR_UNUSED)
{
if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
set_buflocal_cfu_callback(curbuf);
+ return NULL;
}
/// Copy the global 'completefunc' callback function to the buffer-local
@@ -2279,13 +2260,14 @@ void set_buflocal_cfu_callback(buf_T *buf)
/// Invoked when the 'omnifunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-void set_omnifunc_option(buf_T *buf, char **errmsg)
+const char *did_set_omnifunc(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
if (option_set_callback_func(buf->b_p_ofu, &ofu_cb) == FAIL) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
set_buflocal_ofu_callback(buf);
+ return NULL;
}
/// Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc'
@@ -2299,7 +2281,7 @@ void set_buflocal_ofu_callback(buf_T *buf)
/// Invoked when the 'thesaurusfunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-void set_thesaurusfunc_option(char **errmsg)
+const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED)
{
int retval;
@@ -2311,9 +2293,7 @@ void set_thesaurusfunc_option(char **errmsg)
retval = option_set_callback_func(p_tsrfu, &tsrfu_cb);
}
- if (retval == FAIL) {
- *errmsg = e_invarg;
- }
+ return retval == FAIL ? e_invarg : NULL;
}
/// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
@@ -2363,13 +2343,11 @@ static void expand_by_function(int type, char *base)
{
list_T *matchlist = NULL;
dict_T *matchdict = NULL;
- char *funcname;
- pos_T pos;
typval_T rettv;
const int save_State = State;
assert(curbuf != NULL);
- funcname = get_complete_funcname(type);
+ char *funcname = get_complete_funcname(type);
if (*funcname == NUL) {
return;
}
@@ -2382,7 +2360,7 @@ static void expand_by_function(int type, char *base)
args[0].vval.v_number = 0;
args[1].vval.v_string = base != NULL ? base : "";
- pos = curwin->w_cursor;
+ pos_T pos = curwin->w_cursor;
// Lock the text to avoid weird things from happening. Also disallow
// switching to another window, it should not be needed and may end up in
// Insert mode in another buffer.
@@ -2434,7 +2412,7 @@ theend:
}
}
-/// Add a match to the list of matches from VimL object
+/// Add a match to the list of matches from Vimscript object
///
/// @param[in] tv Object to get matches from.
/// @param[in] dir Completion direction.
@@ -2509,14 +2487,11 @@ static void ins_compl_add_list(list_T *const list)
/// Add completions from a dict.
static void ins_compl_add_dict(dict_T *dict)
{
- dictitem_T *di_refresh;
- dictitem_T *di_words;
-
// Check for optional "refresh" item.
compl_opt_refresh_always = false;
- di_refresh = tv_dict_find(dict, S_LEN("refresh"));
+ dictitem_T *di_refresh = tv_dict_find(dict, S_LEN("refresh"));
if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) {
- const char *v = (const char *)di_refresh->di_tv.vval.v_string;
+ const char *v = di_refresh->di_tv.vval.v_string;
if (v != NULL && strcmp(v, "always") == 0) {
compl_opt_refresh_always = true;
@@ -2524,7 +2499,7 @@ static void ins_compl_add_dict(dict_T *dict)
}
// Add completions from a "words" list.
- di_words = tv_dict_find(dict, S_LEN("words"));
+ dictitem_T *di_words = tv_dict_find(dict, S_LEN("words"));
if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) {
ins_compl_add_list(di_words->di_tv.vval.v_list);
}
@@ -2652,7 +2627,7 @@ static void ins_compl_update_sequence_numbers(void)
compl_T *match;
if (compl_dir_forward()) {
- // search backwards for the first valid (!= -1) number.
+ // Search backwards for the first valid (!= -1) number.
// This should normally succeed already at the first loop
// cycle, so it's fast!
for (match = compl_curr_match->cp_prev;
@@ -2672,7 +2647,7 @@ static void ins_compl_update_sequence_numbers(void)
}
} else { // BACKWARD
assert(compl_direction == BACKWARD);
- // search forwards (upwards) for the first valid (!= -1)
+ // Search forwards (upwards) for the first valid (!= -1)
// number. This should normally succeed already at the
// first loop cycle, so it's fast!
for (match = compl_curr_match->cp_next;
@@ -2683,8 +2658,7 @@ static void ins_compl_update_sequence_numbers(void)
}
}
if (match != NULL) {
- // go down and assign all numbers which are not
- // assigned yet
+ // go down and assign all numbers which are not assigned yet
for (match = match->cp_prev;
match && match->cp_number == -1;
match = match->cp_prev) {
@@ -2694,6 +2668,70 @@ static void ins_compl_update_sequence_numbers(void)
}
}
+static int info_add_completion_info(list_T *li)
+{
+ if (compl_first_match == NULL) {
+ return OK;
+ }
+
+ bool forward = compl_dir_forward();
+ compl_T *match = compl_first_match;
+ // There are four cases to consider here:
+ // 1) when just going forward through the menu,
+ // compl_first_match should point to the initial entry with
+ // number zero and CP_ORIGINAL_TEXT flag set
+ // 2) when just going backwards,
+ // compl-first_match should point to the last entry before
+ // the entry with the CP_ORIGINAL_TEXT flag set
+ // 3) when first going forwards and then backwards, e.g.
+ // pressing C-N, C-P, compl_first_match points to the
+ // last entry before the entry with the CP_ORIGINAL_TEXT
+ // flag set and next-entry moves opposite through the list
+ // compared to case 2, so pretend the direction is forward again
+ // 4) when first going backwards and then forwards, e.g.
+ // pressing C-P, C-N, compl_first_match points to the
+ // first entry with the CP_ORIGINAL_TEXT
+ // flag set and next-entry moves in opposite direction through the list
+ // compared to case 1, so pretend the direction is backwards again
+ //
+ // But only do this when the 'noselect' option is not active!
+
+ if (!compl_no_select) {
+ if (forward && !match_at_original_text(match)) {
+ forward = false;
+ } else if (!forward && match_at_original_text(match)) {
+ forward = true;
+ }
+ }
+
+ // Skip the element with the CP_ORIGINAL_TEXT flag at the beginning, in case of
+ // forward completion, or at the end, in case of backward completion.
+ match = forward ? match->cp_next
+ : (compl_no_select && match_at_original_text(match)
+ ? match->cp_prev : match->cp_prev->cp_prev);
+
+ while (match != NULL && !match_at_original_text(match)) {
+ dict_T *di = tv_dict_alloc();
+
+ tv_list_append_dict(li, di);
+ tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
+ tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
+ tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
+ tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(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);
+ }
+
+ match = forward ? match->cp_next : match->cp_prev;
+ }
+
+ return OK;
+}
+
/// Get complete information
static void get_complete_info(list_T *what_list, dict_T *retdict)
{
@@ -2739,29 +2777,9 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
if (ret == OK && (what_flag & CI_WHAT_ITEMS)) {
list_T *li = tv_list_alloc(get_compl_len());
-
ret = tv_dict_add_list(retdict, S_LEN("items"), li);
- if (ret == OK && compl_first_match != NULL) {
- compl_T *match = compl_first_match;
- do {
- if (!match_at_original_text(match)) {
- dict_T *di = tv_dict_alloc();
-
- tv_list_append_dict(li, di);
- tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
- tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
- tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
- tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
- tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(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);
- }
- }
- match = match->cp_next;
- } while (match != NULL && !is_first_match(match));
+ if (ret == OK) {
+ ret = info_add_completion_info(li);
}
}
@@ -2878,20 +2896,20 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
st->dict_f = DICT_EXACT;
}
if (!shortmess(SHM_COMPLETIONSCAN)) {
- msg_hist_off = true; // reset in msg_trunc_attr()
+ msg_hist_off = true; // reset in msg_trunc()
vim_snprintf(IObuff, IOSIZE, _("Scanning: %s"),
st->ins_buf->b_fname == NULL
? buf_spname(st->ins_buf)
: st->ins_buf->b_sfname == NULL
? st->ins_buf->b_fname
: st->ins_buf->b_sfname);
- (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
+ (void)msg_trunc(IObuff, true, HL_ATTR(HLF_R));
}
} else if (*st->e_cpt == NUL) {
status = INS_COMPL_CPT_END;
} else {
if (ctrl_x_mode_line_or_eval()) {
- compl_type = -1;
+ // compl_type = -1;
} else if (*st->e_cpt == 'k' || *st->e_cpt == 's') {
if (*st->e_cpt == 'k') {
compl_type = CTRL_X_DICTIONARY;
@@ -2906,15 +2924,15 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
compl_type = CTRL_X_PATH_PATTERNS;
} else if (*st->e_cpt == 'd') {
compl_type = CTRL_X_PATH_DEFINES;
+ } else if (*st->e_cpt == 'f') {
+ compl_type = CTRL_X_BUFNAMES;
} else if (*st->e_cpt == ']' || *st->e_cpt == 't') {
compl_type = CTRL_X_TAGS;
if (!shortmess(SHM_COMPLETIONSCAN)) {
- msg_hist_off = true; // reset in msg_trunc_attr()
+ msg_hist_off = true; // reset in msg_trunc()
vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags."));
- (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
+ (void)msg_trunc(IObuff, true, HL_ATTR(HLF_R));
}
- } else {
- compl_type = -1;
}
// in any case e_cpt is advanced to the next entry
@@ -2940,7 +2958,7 @@ static void get_next_include_file_completion(int compl_type)
((compl_type == CTRL_X_PATH_DEFINES
&& !(compl_cont_status & CONT_SOL))
? FIND_DEFINE : FIND_ANY),
- 1L, ACTION_EXPAND, 1, MAXLNUM);
+ 1, ACTION_EXPAND, 1, MAXLNUM);
}
/// Get the next set of words matching "compl_pattern" in dictionary or
@@ -2950,11 +2968,11 @@ 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);
} else {
- ins_compl_dictionaries(dict != NULL ? dict
+ 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)),
+ : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)),
compl_pattern,
dict != NULL ? dict_f : 0,
compl_type == CTRL_X_THESAURUS);
@@ -3043,18 +3061,18 @@ static void get_next_spell_completion(linenr_T lnum)
/// @param cur_match_pos current match position
/// @param match_len
/// @param cont_s_ipos next ^X<> will set initial_pos
-static char *ins_comp_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len,
- bool *cont_s_ipos)
+static char *ins_compl_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len,
+ bool *cont_s_ipos)
{
*match_len = 0;
- char *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, false) + cur_match_pos->col;
+ char *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum) + cur_match_pos->col;
int len;
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, false);
+ ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1);
if (!p_paste) {
ptr = skipwhite(ptr);
}
@@ -3082,7 +3100,7 @@ static char *ins_comp_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos
// normal command "J" was used. IOSIZE is always greater than
// compl_length, so the next strncpy always works -- Acevedo
strncpy(IObuff, ptr, (size_t)len); // NOLINT(runtime/printf)
- ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, false);
+ ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1);
tmp_ptr = ptr = skipwhite(ptr);
// Find start of next word.
tmp_ptr = find_word_start(tmp_ptr);
@@ -3151,7 +3169,7 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
}
bool looped_around = false;
int found_new_match = FAIL;
- for (;;) {
+ while (true) {
bool cont_s_ipos = false;
msg_silent++; // Don't want messages for wrapscan.
@@ -3162,7 +3180,7 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
compl_direction, compl_pattern);
} else {
found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
- NULL, compl_direction, compl_pattern, 1L,
+ NULL, compl_direction, compl_pattern, 1,
SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
}
msg_silent--;
@@ -3206,8 +3224,8 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_
continue;
}
int len;
- char *ptr = ins_comp_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
- &len, &cont_s_ipos);
+ char *ptr = ins_compl_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
+ &len, &cont_s_ipos);
if (ptr == NULL) {
continue;
}
@@ -3265,6 +3283,9 @@ static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_
case CTRL_X_SPELL:
get_next_spell_completion(st->first_match_pos.lnum);
break;
+ case CTRL_X_BUFNAMES:
+ get_next_bufname_token();
+ break;
default: // normal ^P/^N and ^X^L
found_new_match = get_next_default_completion(st, ini);
@@ -3282,6 +3303,19 @@ static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_
return found_new_match;
}
+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) {
+ ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0,
+ p_ic ? CP_ICASE : 0, false);
+ }
+ }
+ }
+}
+
/// Get the next expansion(s), using "compl_pattern".
/// The search starts at position "ini" in curbuf and in the direction
/// compl_direction.
@@ -3292,7 +3326,7 @@ static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_
static int ins_compl_get_exp(pos_T *ini)
{
static ins_compl_next_state_T st;
- int i;
+ static bool st_cleared = false;
int found_new_match;
int type = ctrl_x_mode;
@@ -3302,9 +3336,16 @@ static int ins_compl_get_exp(pos_T *ini)
FOR_ALL_BUFFERS(buf) {
buf->b_scanned = false;
}
+ if (!st_cleared) {
+ CLEAR_FIELD(st);
+ st_cleared = true;
+ }
st.found_all = false;
st.ins_buf = curbuf;
- st.e_cpt = (compl_cont_status & CONT_LOCAL) ? "." : curbuf->b_p_cpt;
+ xfree(st.e_cpt_copy);
+ // Make a copy of 'complete', in case the buffer is wiped out.
+ st.e_cpt_copy = xstrdup((compl_cont_status & CONT_LOCAL) ? "." : curbuf->b_p_cpt);
+ st.e_cpt = st.e_cpt_copy;
st.last_match_pos = st.first_match_pos = *ini;
} else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) {
st.ins_buf = curbuf; // In case the buffer was wiped out.
@@ -3315,7 +3356,7 @@ static int ins_compl_get_exp(pos_T *ini)
st.cur_match_pos = compl_dir_forward() ? &st.last_match_pos : &st.first_match_pos;
// For ^N/^P loop over all the flags/windows/buffers in 'complete'
- for (;;) {
+ while (true) {
found_new_match = FAIL;
st.set_match_pos = false;
@@ -3361,7 +3402,7 @@ static int ins_compl_get_exp(pos_T *ini)
compl_started = true;
} else {
// Mark a buffer scanned when it has been scanned completely
- if (type == 0 || type == CTRL_X_PATH_PATTERNS) {
+ if (buf_valid(st.ins_buf) && (type == 0 || type == CTRL_X_PATH_PATTERNS)) {
assert(st.ins_buf);
st.ins_buf->b_scanned = true;
}
@@ -3376,7 +3417,7 @@ static int ins_compl_get_exp(pos_T *ini)
found_new_match = FAIL;
}
- i = -1; // total of matches, unknown
+ int i = -1; // total of matches, unknown
if (found_new_match == FAIL
|| (ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval())) {
i = ins_compl_make_cyclic();
@@ -3387,8 +3428,8 @@ static int ins_compl_get_exp(pos_T *ini)
// just been made cyclic then we have to move compl_curr_match to the
// next or previous entry (if any) -- Acevedo
compl_curr_match = compl_dir_forward()
- ? compl_old_match->cp_next
- : compl_old_match->cp_prev;
+ ? compl_old_match->cp_next
+ : compl_old_match->cp_prev;
if (compl_curr_match == NULL) {
compl_curr_match = compl_old_match;
}
@@ -3426,11 +3467,9 @@ static void ins_compl_update_shown_match(void)
/// Delete the old text being completed.
void ins_compl_delete(void)
{
- int col;
-
// In insert mode: Delete the typed part.
// In replace mode: Put the old characters back, if any.
- col = compl_col + (compl_status_adding() ? compl_length : 0);
+ int col = compl_col + (compl_status_adding() ? compl_length : 0);
if ((int)curwin->w_cursor.col > col) {
if (stop_arrow() == FAIL) {
return;
@@ -3440,7 +3479,7 @@ void ins_compl_delete(void)
// TODO(vim): is this sufficient for redrawing? Redrawing everything
// causes flicker, thus we can't do that.
- changed_cline_bef_curs();
+ changed_cline_bef_curs(curwin);
// clear v:completed_item
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
}
@@ -3484,7 +3523,7 @@ static void ins_compl_show_filename(void)
msg_hist_off = true;
vim_snprintf(IObuff, IOSIZE, "%s %s%s", lead,
s > compl_shown_match->cp_fname ? "<" : "", s);
- msg(IObuff);
+ msg(IObuff, 0);
msg_hist_off = false;
redraw_cmdline = false; // don't overwrite!
}
@@ -3604,6 +3643,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
int num_matches = -1;
int todo = count;
const bool started = compl_started;
+ buf_T *const orig_curbuf = curbuf;
// When user complete function return -1 for findstart which is next
// time of 'always', compl_shown_match become NULL.
@@ -3617,7 +3657,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_restarting) || compl_used_match)) {
+ && (!compl_get_longest || compl_used_match)) {
// Delete old text to be replaced
ins_compl_delete();
}
@@ -3639,6 +3679,12 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
return -1;
}
+ if (curbuf != orig_curbuf) {
+ // In case some completion function switched buffer, don't want to
+ // insert the completion elsewhere.
+ return -1;
+ }
+
// Insert the text of the new completion, or the compl_leader.
if (compl_no_insert && !started) {
ins_bytes(compl_orig_text + get_compl_len());
@@ -3768,15 +3814,13 @@ static bool ins_compl_pum_key(int c)
/// Returns 1 for most keys, height of the popup menu for page-up/down keys.
static int ins_compl_key2count(int c)
{
- int h;
-
if (c == K_EVENT || c == K_COMMAND || c == K_LUA) {
int offset = pum_want.item - pum_selected_item;
return abs(offset);
}
if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN) {
- h = pum_get_height();
+ int h = pum_get_height();
if (h > 3) {
h -= 2; // keep some context
}
@@ -4304,9 +4348,8 @@ static void ins_compl_show_statusmsg(void)
if (edit_submode_extra != NULL) {
if (!p_smd) {
msg_hist_off = true;
- msg_attr((const char *)edit_submode_extra,
- (edit_submode_highl < HLF_COUNT
- ? HL_ATTR(edit_submode_highl) : 0));
+ msg(edit_submode_extra, (edit_submode_highl < HLF_COUNT
+ ? HL_ATTR(edit_submode_highl) : 0));
msg_hist_off = false;
}
} else {
@@ -4320,13 +4363,8 @@ static void ins_compl_show_statusmsg(void)
/// Returns OK if completion was done, FAIL if something failed.
int ins_complete(int c, bool enable_pum)
{
- int n;
- int save_w_wrow;
- int save_w_leftcol;
- int insert_match;
-
compl_direction = ins_compl_key2dir(c);
- insert_match = ins_compl_use_match(c);
+ int insert_match = ins_compl_use_match(c);
if (!compl_started) {
if (ins_compl_start() == FAIL) {
@@ -4340,9 +4378,9 @@ int ins_complete(int c, bool enable_pum)
compl_shows_dir = compl_direction;
// Find next match (and following matches).
- save_w_wrow = curwin->w_wrow;
- save_w_leftcol = curwin->w_leftcol;
- n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false);
+ int save_w_wrow = curwin->w_wrow;
+ int save_w_leftcol = curwin->w_leftcol;
+ int n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false);
if (n > 1) { // all matches have been found
compl_matches = n;