mirror of
https://github.com/neovim/neovim.git
synced 2025-11-16 23:31:19 +00:00
vim-patch:9.1.1603: completion: cannot use autoloaded funcs in 'complete' F{func}
Problem: completion: cannot use autoloaded funcs in 'complete' F{func}
(Maxim Kim)
Solution: Make it work (Girish Palya)
fixes: vim/vim#17869
closes: vim/vim#17885
1bfe86a7d3
Cherry-pick Test_omni_autoload() from patch 8.2.3223.
Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
@@ -68,6 +68,7 @@
|
|||||||
#include "nvim/help.h"
|
#include "nvim/help.h"
|
||||||
#include "nvim/indent.h"
|
#include "nvim/indent.h"
|
||||||
#include "nvim/indent_c.h"
|
#include "nvim/indent_c.h"
|
||||||
|
#include "nvim/insexpand.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/map_defs.h"
|
#include "nvim/map_defs.h"
|
||||||
#include "nvim/mapping.h"
|
#include "nvim/mapping.h"
|
||||||
@@ -2104,6 +2105,8 @@ void free_buf_options(buf_T *buf, bool free_p_ff)
|
|||||||
callback_free(&buf->b_ofu_cb);
|
callback_free(&buf->b_ofu_cb);
|
||||||
clear_string_option(&buf->b_p_tsrfu);
|
clear_string_option(&buf->b_p_tsrfu);
|
||||||
callback_free(&buf->b_tsrfu_cb);
|
callback_free(&buf->b_tsrfu_cb);
|
||||||
|
clear_cpt_callbacks(&buf->b_p_cpt_cb, buf->b_p_cpt_count);
|
||||||
|
buf->b_p_cpt_count = 0;
|
||||||
clear_string_option(&buf->b_p_gefm);
|
clear_string_option(&buf->b_p_gefm);
|
||||||
clear_string_option(&buf->b_p_gp);
|
clear_string_option(&buf->b_p_gp);
|
||||||
clear_string_option(&buf->b_p_mp);
|
clear_string_option(&buf->b_p_mp);
|
||||||
|
|||||||
@@ -540,6 +540,8 @@ struct file_buffer {
|
|||||||
#ifdef BACKSLASH_IN_FILENAME
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
char *b_p_csl; ///< 'completeslash'
|
char *b_p_csl; ///< 'completeslash'
|
||||||
#endif
|
#endif
|
||||||
|
Callback *b_p_cpt_cb; ///< F{func} in 'complete' callback
|
||||||
|
int b_p_cpt_count; ///< Count of values in 'complete'
|
||||||
char *b_p_cfu; ///< 'completefunc'
|
char *b_p_cfu; ///< 'completefunc'
|
||||||
Callback b_cfu_cb; ///< 'completefunc' callback
|
Callback b_cfu_cb; ///< 'completefunc' callback
|
||||||
char *b_p_ofu; ///< 'omnifunc'
|
char *b_p_ofu; ///< 'omnifunc'
|
||||||
|
|||||||
@@ -4795,6 +4795,9 @@ bool garbage_collect(bool testing)
|
|||||||
ABORTING(set_ref_in_callback)(&buf->b_tsrfu_cb, copyID, NULL, NULL);
|
ABORTING(set_ref_in_callback)(&buf->b_tsrfu_cb, copyID, NULL, NULL);
|
||||||
ABORTING(set_ref_in_callback)(&buf->b_tfu_cb, copyID, NULL, NULL);
|
ABORTING(set_ref_in_callback)(&buf->b_tfu_cb, copyID, NULL, NULL);
|
||||||
ABORTING(set_ref_in_callback)(&buf->b_ffu_cb, copyID, NULL, NULL);
|
ABORTING(set_ref_in_callback)(&buf->b_ffu_cb, copyID, NULL, NULL);
|
||||||
|
if (!abort && buf->b_p_cpt_cb != NULL) {
|
||||||
|
ABORTING(set_ref_in_cpt_callbacks)(buf->b_p_cpt_cb, buf->b_p_cpt_count, copyID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'completefunc', 'omnifunc' and 'thesaurusfunc' callbacks
|
// 'completefunc', 'omnifunc' and 'thesaurusfunc' callbacks
|
||||||
|
|||||||
@@ -2821,9 +2821,31 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count the number of entries in the 'complete' option (curbuf->b_p_cpt).
|
||||||
|
/// Each non-empty, comma-separated segment is counted as one entry.
|
||||||
|
static int get_cpt_sources_count(void)
|
||||||
|
{
|
||||||
|
char dummy[LSIZE];
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (char *p = curbuf->b_p_cpt; *p != NUL;) {
|
||||||
|
while (*p == ',' || *p == ' ') {
|
||||||
|
p++; // Skip delimiters
|
||||||
|
}
|
||||||
|
if (*p != NUL) {
|
||||||
|
(void)copy_option_part(&p, dummy, LSIZE, ","); // Advance p
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static Callback cfu_cb; ///< 'completefunc' callback function
|
static Callback cfu_cb; ///< 'completefunc' callback function
|
||||||
static Callback ofu_cb; ///< 'omnifunc' callback function
|
static Callback ofu_cb; ///< 'omnifunc' callback function
|
||||||
static Callback tsrfu_cb; ///< 'thesaurusfunc' callback function
|
static Callback tsrfu_cb; ///< 'thesaurusfunc' callback function
|
||||||
|
static Callback *cpt_cb; ///< Callback functions associated with F{func}
|
||||||
|
static int cpt_cb_count; ///< Number of cpt callbacks
|
||||||
|
|
||||||
/// Copy a global callback function to a buffer local callback.
|
/// Copy a global callback function to a buffer local callback.
|
||||||
static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb)
|
static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb)
|
||||||
@@ -2876,6 +2898,101 @@ void set_buflocal_ofu_callback(buf_T *buf)
|
|||||||
copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb);
|
copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Free an array of 'complete' F{func} callbacks and set the pointer to NULL.
|
||||||
|
void clear_cpt_callbacks(Callback **callbacks, int count)
|
||||||
|
{
|
||||||
|
if (callbacks == NULL || *callbacks == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
callback_free(&(*callbacks)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
XFREE_CLEAR(*callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copies a list of Callback structs from src to *dest, clearing any existing
|
||||||
|
/// entries and allocating memory for the destination.
|
||||||
|
static void copy_cpt_callbacks(Callback **dest, int *dest_cnt, Callback *src, int cnt)
|
||||||
|
{
|
||||||
|
if (cnt == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_cpt_callbacks(dest, *dest_cnt);
|
||||||
|
*dest = xcalloc((size_t)cnt, sizeof(Callback));
|
||||||
|
*dest_cnt = cnt;
|
||||||
|
|
||||||
|
for (int i = 0; i < cnt; i++) {
|
||||||
|
if (src[i].type != kCallbackNone) {
|
||||||
|
callback_copy(&(*dest)[i], &src[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy global 'complete' F{func} callbacks into the given buffer's local
|
||||||
|
/// callback array. Clears any existing buffer-local callbacks first.
|
||||||
|
void set_buflocal_cpt_callbacks(buf_T *buf)
|
||||||
|
{
|
||||||
|
if (buf == NULL || cpt_cb_count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
copy_cpt_callbacks(&buf->b_p_cpt_cb, &buf->b_p_cpt_count, cpt_cb, cpt_cb_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse 'complete' option and initialize F{func} callbacks.
|
||||||
|
/// Frees any existing callbacks and allocates new ones.
|
||||||
|
/// Only F{func} entries are processed; others are ignored.
|
||||||
|
int set_cpt_callbacks(optset_T *args)
|
||||||
|
{
|
||||||
|
bool local = (args->os_flags & OPT_LOCAL) != 0;
|
||||||
|
|
||||||
|
if (curbuf == NULL) {
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_cpt_callbacks(&curbuf->b_p_cpt_cb, curbuf->b_p_cpt_count);
|
||||||
|
curbuf->b_p_cpt_count = 0;
|
||||||
|
|
||||||
|
int count = get_cpt_sources_count();
|
||||||
|
if (count == 0) {
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
curbuf->b_p_cpt_cb = xcalloc((size_t)count, sizeof(Callback));
|
||||||
|
curbuf->b_p_cpt_count = count;
|
||||||
|
|
||||||
|
char buf[LSIZE];
|
||||||
|
int idx = 0;
|
||||||
|
for (char *p = curbuf->b_p_cpt; *p != NUL;) {
|
||||||
|
while (*p == ',' || *p == ' ') {
|
||||||
|
p++; // Skip delimiters
|
||||||
|
}
|
||||||
|
if (*p != NUL) {
|
||||||
|
size_t slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p
|
||||||
|
if (slen > 0 && buf[0] == 'F' && buf[1] != NUL) {
|
||||||
|
char *caret = vim_strchr(buf, '^');
|
||||||
|
if (caret != NULL) {
|
||||||
|
*caret = NUL;
|
||||||
|
}
|
||||||
|
if (option_set_callback_func(buf + 1, &curbuf->b_p_cpt_cb[idx]) != OK) {
|
||||||
|
curbuf->b_p_cpt_cb[idx].type = kCallbackNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!local) { // ':set' used insted of ':setlocal'
|
||||||
|
// Cache the callback array
|
||||||
|
copy_cpt_callbacks(&cpt_cb, &cpt_cb_count, curbuf->b_p_cpt_cb,
|
||||||
|
curbuf->b_p_cpt_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse the 'thesaurusfunc' option value and set the callback function.
|
/// Parse the 'thesaurusfunc' option value and set the callback function.
|
||||||
/// Invoked when the 'thesaurusfunc' option is set. The option value can be a
|
/// 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
|
/// name of a function (string), or function(<name>) or funcref(<name>) or a
|
||||||
@@ -2900,6 +3017,22 @@ const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED)
|
|||||||
return retval == FAIL ? e_invarg : NULL;
|
return retval == FAIL ? e_invarg : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark "copyID" references in an array of F{func} callbacks so that they are
|
||||||
|
/// not garbage collected.
|
||||||
|
bool set_ref_in_cpt_callbacks(Callback *callbacks, int count, int copyID)
|
||||||
|
{
|
||||||
|
bool abort = false;
|
||||||
|
|
||||||
|
if (callbacks == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
abort = abort || set_ref_in_callback(&callbacks[i], copyID, NULL, NULL);
|
||||||
|
}
|
||||||
|
return abort;
|
||||||
|
}
|
||||||
|
|
||||||
/// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
|
/// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
|
||||||
/// "copyID" so that they are not garbage collected.
|
/// "copyID" so that they are not garbage collected.
|
||||||
bool set_ref_in_insexpand_funcs(int copyID)
|
bool set_ref_in_insexpand_funcs(int copyID)
|
||||||
@@ -2907,6 +3040,7 @@ bool set_ref_in_insexpand_funcs(int copyID)
|
|||||||
bool abort = set_ref_in_callback(&cfu_cb, copyID, NULL, NULL);
|
bool abort = set_ref_in_callback(&cfu_cb, copyID, NULL, NULL);
|
||||||
abort = abort || set_ref_in_callback(&ofu_cb, copyID, NULL, NULL);
|
abort = abort || set_ref_in_callback(&ofu_cb, copyID, NULL, NULL);
|
||||||
abort = abort || set_ref_in_callback(&tsrfu_cb, copyID, NULL, NULL);
|
abort = abort || set_ref_in_callback(&tsrfu_cb, copyID, NULL, NULL);
|
||||||
|
abort = abort || set_ref_in_cpt_callbacks(cpt_cb, cpt_cb_count, copyID);
|
||||||
|
|
||||||
return abort;
|
return abort;
|
||||||
}
|
}
|
||||||
@@ -3663,7 +3797,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar
|
|||||||
// compl_type = -1;
|
// compl_type = -1;
|
||||||
} else if (*st->e_cpt == 'F' || *st->e_cpt == 'o') {
|
} else if (*st->e_cpt == 'F' || *st->e_cpt == 'o') {
|
||||||
compl_type = CTRL_X_FUNCTION;
|
compl_type = CTRL_X_FUNCTION;
|
||||||
st->func_cb = get_callback_if_cpt_func(st->e_cpt);
|
st->func_cb = get_callback_if_cpt_func(st->e_cpt, cpt_sources_index);
|
||||||
if (!st->func_cb) {
|
if (!st->func_cb) {
|
||||||
compl_type = -1;
|
compl_type = -1;
|
||||||
}
|
}
|
||||||
@@ -4326,28 +4460,25 @@ static void get_register_completion(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the callback function associated with "p" if it points to a
|
/// Return the callback function associated with "p" if it refers to a
|
||||||
/// userfunc.
|
/// user-defined function in the 'complete' option.
|
||||||
static Callback *get_callback_if_cpt_func(char *p)
|
/// The "idx" parameter is used for indexing callback entries.
|
||||||
|
static Callback *get_callback_if_cpt_func(char *p, int idx)
|
||||||
{
|
{
|
||||||
static Callback cb;
|
|
||||||
char buf[LSIZE];
|
|
||||||
|
|
||||||
if (*p == 'o') {
|
if (*p == 'o') {
|
||||||
return &curbuf->b_ofu_cb;
|
return &curbuf->b_ofu_cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == 'F') {
|
if (*p == 'F') {
|
||||||
if (*++p != ',' && *p != NUL) {
|
if (*++p != ',' && *p != NUL) {
|
||||||
callback_free(&cb);
|
// 'F{func}' case
|
||||||
size_t slen = copy_option_part(&p, buf, LSIZE, ",");
|
return curbuf->b_p_cpt_cb[idx].type != kCallbackNone
|
||||||
if (slen > 0 && option_set_callback_func(buf, &cb)) {
|
? &curbuf->b_p_cpt_cb[idx] : NULL;
|
||||||
return &cb;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
} else {
|
} else {
|
||||||
return &curbuf->b_cfu_cb;
|
return &curbuf->b_cfu_cb; // 'cfu'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4480,7 +4611,7 @@ static void prepare_cpt_compl_funcs(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Callback *cb = get_callback_if_cpt_func(p);
|
Callback *cb = get_callback_if_cpt_func(p, idx);
|
||||||
if (cb) {
|
if (cb) {
|
||||||
int startcol;
|
int startcol;
|
||||||
if (get_userdefined_compl_info(curwin->w_cursor.col, cb, &startcol) == FAIL) {
|
if (get_userdefined_compl_info(curwin->w_cursor.col, cb, &startcol) == FAIL) {
|
||||||
@@ -6050,6 +6181,7 @@ void free_insexpand_stuff(void)
|
|||||||
callback_free(&cfu_cb);
|
callback_free(&cfu_cb);
|
||||||
callback_free(&ofu_cb);
|
callback_free(&ofu_cb);
|
||||||
callback_free(&tsrfu_cb);
|
callback_free(&tsrfu_cb);
|
||||||
|
clear_cpt_callbacks(&cpt_cb, cpt_cb_count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -6075,47 +6207,35 @@ static void cpt_sources_clear(void)
|
|||||||
/// Setup completion sources.
|
/// Setup completion sources.
|
||||||
static void setup_cpt_sources(void)
|
static void setup_cpt_sources(void)
|
||||||
{
|
{
|
||||||
char buf[LSIZE];
|
|
||||||
|
|
||||||
// Make a copy of 'cpt' in case the buffer gets wiped out
|
|
||||||
char *cpt = xstrdup(curbuf->b_p_cpt);
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for (char *p = cpt; *p;) {
|
|
||||||
while (*p == ',' || *p == ' ') { // Skip delimiters
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
if (*p) { // If not end of string, count this segment
|
|
||||||
(void)copy_option_part(&p, buf, LSIZE, ","); // Advance p
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count == 0) {
|
|
||||||
goto theend;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpt_sources_clear();
|
cpt_sources_clear();
|
||||||
cpt_sources_count = count;
|
|
||||||
|
int count = get_cpt_sources_count();
|
||||||
|
if (count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cpt_sources_array = xcalloc((size_t)count, sizeof(cpt_source_T));
|
cpt_sources_array = xcalloc((size_t)count, sizeof(cpt_source_T));
|
||||||
|
|
||||||
|
char buf[LSIZE];
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (char *p = cpt; *p;) {
|
for (char *p = curbuf->b_p_cpt; *p;) {
|
||||||
while (*p == ',' || *p == ' ') { // Skip delimiters
|
while (*p == ',' || *p == ' ') { // Skip delimiters
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
if (*p) { // If not end of string, count this segment
|
if (*p) { // If not end of string, count this segment
|
||||||
memset(buf, 0, LSIZE);
|
memset(buf, 0, LSIZE);
|
||||||
size_t slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p
|
size_t slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p
|
||||||
char *t;
|
if (slen > 0) {
|
||||||
if (slen > 0 && (t = vim_strchr(buf, '^')) != NULL) {
|
char *caret = vim_strchr(buf, '^');
|
||||||
cpt_sources_array[idx].cs_max_matches = atoi(t + 1);
|
if (caret != NULL) {
|
||||||
|
cpt_sources_array[idx].cs_max_matches = atoi(caret + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
theend:
|
cpt_sources_count = count;
|
||||||
xfree(cpt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if any of the completion sources have 'refresh' set to 'always'.
|
/// Return true if any of the completion sources have 'refresh' set to 'always'.
|
||||||
@@ -6248,7 +6368,7 @@ static void cpt_compl_refresh(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cpt_sources_array[cpt_sources_index].cs_refresh_always) {
|
if (cpt_sources_array[cpt_sources_index].cs_refresh_always) {
|
||||||
Callback *cb = get_callback_if_cpt_func(p);
|
Callback *cb = get_callback_if_cpt_func(p, cpt_sources_index);
|
||||||
if (cb) {
|
if (cb) {
|
||||||
compl_curr_match = remove_old_matches();
|
compl_curr_match = remove_old_matches();
|
||||||
int startcol;
|
int startcol;
|
||||||
|
|||||||
@@ -5109,6 +5109,7 @@ void buf_copy_options(buf_T *buf, int flags)
|
|||||||
}
|
}
|
||||||
buf->b_p_cpt = xstrdup(p_cpt);
|
buf->b_p_cpt = xstrdup(p_cpt);
|
||||||
COPY_OPT_SCTX(buf, kBufOptComplete);
|
COPY_OPT_SCTX(buf, kBufOptComplete);
|
||||||
|
set_buflocal_cpt_callbacks(buf);
|
||||||
#ifdef BACKSLASH_IN_FILENAME
|
#ifdef BACKSLASH_IN_FILENAME
|
||||||
buf->b_p_csl = xstrdup(p_csl);
|
buf->b_p_csl = xstrdup(p_csl);
|
||||||
COPY_OPT_SCTX(buf, kBufOptCompleteslash);
|
COPY_OPT_SCTX(buf, kBufOptCompleteslash);
|
||||||
|
|||||||
@@ -118,6 +118,15 @@ char *illegal_char(char *errbuf, size_t errbuflen, int c)
|
|||||||
return errbuf;
|
return errbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *illegal_char_after_chr(char *errbuf, size_t errbuflen, int c)
|
||||||
|
{
|
||||||
|
if (errbuf == NULL) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
vim_snprintf(errbuf, errbuflen, _(e_illegal_character_after_chr), c);
|
||||||
|
return errbuf;
|
||||||
|
}
|
||||||
|
|
||||||
/// Check string options in a buffer for NULL value.
|
/// Check string options in a buffer for NULL value.
|
||||||
void check_buf_options(buf_T *buf)
|
void check_buf_options(buf_T *buf)
|
||||||
{
|
{
|
||||||
@@ -902,9 +911,8 @@ const char *did_set_complete(optset_T *args)
|
|||||||
}
|
}
|
||||||
if (char_before != NUL) {
|
if (char_before != NUL) {
|
||||||
if (args->os_errbuf != NULL) {
|
if (args->os_errbuf != NULL) {
|
||||||
vim_snprintf(args->os_errbuf, args->os_errbuflen,
|
return illegal_char_after_chr(args->os_errbuf, args->os_errbuflen,
|
||||||
_(e_illegal_character_after_chr), char_before);
|
char_before);
|
||||||
return args->os_errbuf;
|
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -913,6 +921,10 @@ const char *did_set_complete(optset_T *args)
|
|||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (set_cpt_callbacks(args) != OK) {
|
||||||
|
return illegal_char_after_chr(args->os_errbuf, args->os_errbuflen, 'F');
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -178,6 +178,38 @@ func Test_omni_throw()
|
|||||||
set omnifunc= complete&
|
set omnifunc= complete&
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_omni_autoload()
|
||||||
|
let save_rtp = &rtp
|
||||||
|
set rtp=Xruntime/some
|
||||||
|
let dir = 'Xruntime/some/autoload'
|
||||||
|
call mkdir(dir, 'pR')
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
func omni#Func(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return ['match']
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
eval 1 + 2
|
||||||
|
END
|
||||||
|
call writefile(lines, dir .. '/omni.vim')
|
||||||
|
|
||||||
|
new
|
||||||
|
setlocal omnifunc=omni#Func
|
||||||
|
call feedkeys("i\<C-X>\<C-O>\<Esc>", 'xt')
|
||||||
|
|
||||||
|
setlocal complete=.,Fomni#Func
|
||||||
|
call feedkeys("S\<C-N>\<Esc>", 'xt')
|
||||||
|
setlocal complete&
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
set omnifunc=
|
||||||
|
let &rtp = save_rtp
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_completefunc_args()
|
func Test_completefunc_args()
|
||||||
let s:args = []
|
let s:args = []
|
||||||
func! CompleteFunc(findstart, base)
|
func! CompleteFunc(findstart, base)
|
||||||
@@ -2773,6 +2805,15 @@ func Test_omnifunc_callback()
|
|||||||
call assert_equal([[1, ''], [0, 'script1']], g:OmniFunc3Args)
|
call assert_equal([[1, ''], [0, 'script1']], g:OmniFunc3Args)
|
||||||
bw!
|
bw!
|
||||||
|
|
||||||
|
set complete=Fs:OmniFunc3
|
||||||
|
new
|
||||||
|
call setline(1, 'script1')
|
||||||
|
let g:OmniFunc3Args = []
|
||||||
|
call feedkeys("A\<C-N>\<Esc>", 'x')
|
||||||
|
call assert_equal([[1, ''], [0, 'script1']], g:OmniFunc3Args)
|
||||||
|
bw!
|
||||||
|
set complete&
|
||||||
|
|
||||||
let &omnifunc = 's:OmniFunc3'
|
let &omnifunc = 's:OmniFunc3'
|
||||||
new
|
new
|
||||||
call setline(1, 'script2')
|
call setline(1, 'script2')
|
||||||
@@ -5437,4 +5478,50 @@ func Test_autocomplete_timer()
|
|||||||
unlet g:CallCount
|
unlet g:CallCount
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func s:TestCompleteScriptLocal(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return ['foo', 'foobar']
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Issue 17869
|
||||||
|
func Test_scriplocal_autoload_func()
|
||||||
|
let save_rtp = &rtp
|
||||||
|
set rtp=Xruntime/some
|
||||||
|
let dir = 'Xruntime/some/autoload'
|
||||||
|
call mkdir(dir, 'pR')
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
func compl#Func(findstart, base)
|
||||||
|
if a:findstart
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return ['match', 'matchfoo']
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
END
|
||||||
|
call writefile(lines, dir .. '/compl.vim')
|
||||||
|
|
||||||
|
call Ntest_override("char_avail", 1)
|
||||||
|
new
|
||||||
|
inoremap <buffer> <F2> <Cmd>let b:matches = complete_info(["matches"]).matches<CR>
|
||||||
|
set autocomplete
|
||||||
|
|
||||||
|
setlocal complete=.,Fcompl#Func
|
||||||
|
call feedkeys("im\<F2>\<Esc>0", 'xt!')
|
||||||
|
call assert_equal(['match', 'matchfoo'], b:matches->mapnew('v:val.word'))
|
||||||
|
|
||||||
|
setlocal complete=.,F<SID>TestCompleteScriptLocal
|
||||||
|
call feedkeys("Sf\<F2>\<Esc>0", 'xt!')
|
||||||
|
call assert_equal(['foo', 'foobar'], b:matches->mapnew('v:val.word'))
|
||||||
|
|
||||||
|
setlocal complete&
|
||||||
|
set autocomplete&
|
||||||
|
bwipe!
|
||||||
|
call Ntest_override("char_avail", 0)
|
||||||
|
let &rtp = save_rtp
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
|
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
|
||||||
|
|||||||
@@ -290,11 +290,17 @@ func Test_complete()
|
|||||||
set complete=.,w,b,u,k,s,i,d,],t,U,F,o
|
set complete=.,w,b,u,k,s,i,d,],t,U,F,o
|
||||||
set complete=.
|
set complete=.
|
||||||
set complete=.^10,t^0
|
set complete=.^10,t^0
|
||||||
set complete+=Ffuncref('foo'\\,\ [10])
|
|
||||||
set complete=Ffuncref('foo'\\,\ [10])^10
|
func Foo(a, b)
|
||||||
|
return ''
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
set complete+=Ffuncref('Foo'\\,\ [10])
|
||||||
|
set complete=Ffuncref('Foo'\\,\ [10])^10
|
||||||
set complete&
|
set complete&
|
||||||
set complete+=Ffunction('g:foo'\\,\ [10\\,\ 20])
|
set complete+=Ffunction('g:Foo'\\,\ [10\\,\ 20])
|
||||||
set complete&
|
set complete&
|
||||||
|
delfunc Foo
|
||||||
endfun
|
endfun
|
||||||
|
|
||||||
func Test_set_completion()
|
func Test_set_completion()
|
||||||
|
|||||||
Reference in New Issue
Block a user