Skip to content

Commit 1bfe86a

Browse files
girishjichrisbra
authored andcommitted
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: #17869 closes: #17885 Signed-off-by: Girish Palya <girishji@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent 7132935 commit 1bfe86a

File tree

10 files changed

+297
-61
lines changed

10 files changed

+297
-61
lines changed

src/buffer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,8 @@ free_buf_options(
25092509
free_callback(&buf->b_ofu_cb);
25102510
clear_string_option(&buf->b_p_tsrfu);
25112511
free_callback(&buf->b_tsrfu_cb);
2512+
clear_cpt_callbacks(&buf->b_p_cpt_cb, buf->b_p_cpt_count);
2513+
buf->b_p_cpt_count = 0;
25122514
#endif
25132515
#ifdef FEAT_QUICKFIX
25142516
clear_string_option(&buf->b_p_gefm);

src/evalbuffer.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ set_ref_in_buffers(int copyID)
4242
abort = abort || set_ref_in_callback(&bp->b_ofu_cb, copyID);
4343
if (!abort)
4444
abort = abort || set_ref_in_callback(&bp->b_tsrfu_cb, copyID);
45+
if (!abort && bp->b_p_cpt_cb != NULL)
46+
abort = abort || set_ref_in_cpt_callbacks(bp->b_p_cpt_cb,
47+
bp->b_p_cpt_count, copyID);
4548
#endif
4649
if (!abort)
4750
abort = abort || set_ref_in_callback(&bp->b_tfu_cb, copyID);

src/insexpand.c

Lines changed: 194 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static void ins_compl_add_list(list_T *list);
273273
static void ins_compl_add_dict(dict_T *dict);
274274
static int get_userdefined_compl_info(colnr_T curs_col, callback_T *cb, int *startcol);
275275
static void get_cpt_func_completion_matches(callback_T *cb);
276-
static callback_T *get_callback_if_cpt_func(char_u *p);
276+
static callback_T *get_callback_if_cpt_func(char_u *p, int idx);
277277
# endif
278278
static int setup_cpt_sources(void);
279279
static int is_cpt_func_refresh_always(void);
@@ -3191,12 +3191,40 @@ ins_compl_next_buf(buf_T *buf, int flag)
31913191
return buf;
31923192
}
31933193

3194+
/*
3195+
* Count the number of entries in the 'complete' option (curbuf->b_p_cpt).
3196+
* Each non-empty, comma-separated segment is counted as one entry.
3197+
*/
3198+
static int
3199+
get_cpt_sources_count(void)
3200+
{
3201+
char_u dummy[LSIZE];
3202+
int count = 0;
3203+
char_u *p;
3204+
3205+
for (p = curbuf->b_p_cpt; *p != NUL; )
3206+
{
3207+
while (*p == ',' || *p == ' ')
3208+
p++; // Skip delimiters
3209+
3210+
if (*p != NUL)
3211+
{
3212+
(void)copy_option_part(&p, dummy, LSIZE, ","); // Advance p
3213+
count++;
3214+
}
3215+
}
3216+
3217+
return count;
3218+
}
3219+
31943220
#ifdef FEAT_COMPL_FUNC
31953221

31963222
# ifdef FEAT_EVAL
31973223
static callback_T cfu_cb; // 'completefunc' callback function
31983224
static callback_T ofu_cb; // 'omnifunc' callback function
31993225
static callback_T tsrfu_cb; // 'thesaurusfunc' callback function
3226+
static callback_T *cpt_cb; // Callback functions associated with F{func}
3227+
static int cpt_cb_count; // Number of cpt callbacks
32003228
# endif
32013229

32023230
/*
@@ -3267,6 +3295,124 @@ set_buflocal_ofu_callback(buf_T *buf UNUSED)
32673295
# endif
32683296
}
32693297

3298+
/*
3299+
* Free an array of 'complete' F{func} callbacks and set the pointer to NULL.
3300+
*/
3301+
void
3302+
clear_cpt_callbacks(callback_T **callbacks, int count)
3303+
{
3304+
if (callbacks == NULL || *callbacks == NULL)
3305+
return;
3306+
3307+
for (int i = 0; i < count; i++)
3308+
free_callback(&(*callbacks)[i]);
3309+
3310+
VIM_CLEAR(*callbacks);
3311+
}
3312+
3313+
/*
3314+
* Copies a list of callback_T structs from src to *dest, clearing any existing
3315+
* entries and allocating memory for the destination.
3316+
*/
3317+
static int
3318+
copy_cpt_callbacks(callback_T **dest, int *dest_cnt, callback_T *src, int cnt)
3319+
{
3320+
if (cnt == 0)
3321+
return OK;
3322+
3323+
clear_cpt_callbacks(dest, *dest_cnt);
3324+
*dest_cnt = 0;
3325+
3326+
*dest = ALLOC_CLEAR_MULT(callback_T, cnt);
3327+
if (*dest == NULL)
3328+
return FAIL;
3329+
3330+
*dest_cnt = cnt;
3331+
3332+
for (int i = 0; i < cnt; i++)
3333+
if (src[i].cb_name != NULL && *(src[i].cb_name) != NUL)
3334+
copy_callback(&(*dest)[i], &src[i]);
3335+
3336+
return OK;
3337+
}
3338+
3339+
/*
3340+
* Copy global 'complete' F{func} callbacks into the given buffer's local
3341+
* callback array. Clears any existing buffer-local callbacks first.
3342+
*/
3343+
void
3344+
set_buflocal_cpt_callbacks(buf_T *buf UNUSED)
3345+
{
3346+
#ifdef FEAT_EVAL
3347+
if (buf == NULL || cpt_cb_count == 0)
3348+
return;
3349+
(void)copy_cpt_callbacks(&buf->b_p_cpt_cb, &buf->b_p_cpt_count, cpt_cb,
3350+
cpt_cb_count);
3351+
#endif
3352+
}
3353+
3354+
/*
3355+
* Parse 'complete' option and initialize F{func} callbacks.
3356+
* Frees any existing callbacks and allocates new ones.
3357+
* Only F{func} entries are processed; others are ignored.
3358+
*/
3359+
int
3360+
set_cpt_callbacks(optset_T *args)
3361+
{
3362+
char_u buf[LSIZE];
3363+
char_u *p;
3364+
int idx = 0;
3365+
int slen;
3366+
int count;
3367+
int local = (args->os_flags & OPT_LOCAL) != 0;
3368+
3369+
if (curbuf == NULL)
3370+
return FAIL;
3371+
3372+
clear_cpt_callbacks(&curbuf->b_p_cpt_cb, curbuf->b_p_cpt_count);
3373+
curbuf->b_p_cpt_count = 0;
3374+
3375+
count = get_cpt_sources_count();
3376+
if (count == 0)
3377+
return OK;
3378+
3379+
curbuf->b_p_cpt_cb = ALLOC_CLEAR_MULT(callback_T, count);
3380+
if (curbuf->b_p_cpt_cb == NULL)
3381+
return FAIL;
3382+
curbuf->b_p_cpt_count = count;
3383+
3384+
for (p = curbuf->b_p_cpt; *p != NUL; )
3385+
{
3386+
while (*p == ',' || *p == ' ')
3387+
p++; // Skip delimiters
3388+
3389+
if (*p != NUL)
3390+
{
3391+
slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p
3392+
if (slen > 0 && buf[0] == 'F' && buf[1] != NUL)
3393+
{
3394+
char_u *caret;
3395+
caret = vim_strchr(buf, '^');
3396+
if (caret != NULL)
3397+
*caret = NUL;
3398+
3399+
if (option_set_callback_func(buf + 1, &curbuf->b_p_cpt_cb[idx])
3400+
!= OK)
3401+
curbuf->b_p_cpt_cb[idx].cb_name = NULL;
3402+
}
3403+
idx++;
3404+
}
3405+
}
3406+
3407+
if (!local) // ':set' used insted of ':setlocal'
3408+
// Cache the callback array
3409+
if (copy_cpt_callbacks(&cpt_cb, &cpt_cb_count, curbuf->b_p_cpt_cb,
3410+
curbuf->b_p_cpt_count) != OK)
3411+
return FAIL;
3412+
3413+
return OK;
3414+
}
3415+
32703416
/*
32713417
* Parse the 'thesaurusfunc' option value and set the callback function.
32723418
* Invoked when the 'thesaurusfunc' option is set. The option value can be a
@@ -3294,6 +3440,23 @@ did_set_thesaurusfunc(optset_T *args UNUSED)
32943440
return retval == FAIL ? e_invalid_argument : NULL;
32953441
}
32963442

3443+
/*
3444+
* Mark "copyID" references in an array of F{func} callbacks so that they are
3445+
* not garbage collected.
3446+
*/
3447+
int
3448+
set_ref_in_cpt_callbacks(callback_T *callbacks, int count, int copyID)
3449+
{
3450+
int abort = FALSE;
3451+
3452+
if (callbacks == NULL)
3453+
return FALSE;
3454+
3455+
for (int i = 0; i < count; i++)
3456+
abort = abort || set_ref_in_callback(&callbacks[i], copyID);
3457+
return abort;
3458+
}
3459+
32973460
/*
32983461
* Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
32993462
* "copyID" so that they are not garbage collected.
@@ -3304,6 +3467,7 @@ set_ref_in_insexpand_funcs(int copyID)
33043467
int abort = set_ref_in_callback(&cfu_cb, copyID);
33053468
abort = abort || set_ref_in_callback(&ofu_cb, copyID);
33063469
abort = abort || set_ref_in_callback(&tsrfu_cb, copyID);
3470+
abort = abort || set_ref_in_cpt_callbacks(cpt_cb, cpt_cb_count, copyID);
33073471

33083472
return abort;
33093473
}
@@ -4233,7 +4397,7 @@ process_next_cpt_value(
42334397
else if (*st->e_cpt == 'F' || *st->e_cpt == 'o')
42344398
{
42354399
compl_type = CTRL_X_FUNCTION;
4236-
st->func_cb = get_callback_if_cpt_func(st->e_cpt);
4400+
st->func_cb = get_callback_if_cpt_func(st->e_cpt, cpt_sources_index);
42374401
if (!st->func_cb)
42384402
compl_type = -1;
42394403
}
@@ -4915,31 +5079,28 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
49155079

49165080
#ifdef FEAT_COMPL_FUNC
49175081
/*
4918-
* Return the callback function associated with "p" if it points to a
4919-
* userfunc.
5082+
* Return the callback function associated with "p" if it refers to a
5083+
* user-defined function in the 'complete' option.
5084+
* The "idx" parameter is used for indexing callback entries.
49205085
*/
49215086
static callback_T *
4922-
get_callback_if_cpt_func(char_u *p)
5087+
get_callback_if_cpt_func(char_u *p, int idx)
49235088
{
4924-
static callback_T cb;
4925-
char_u buf[LSIZE];
4926-
int slen;
4927-
49285089
if (*p == 'o')
49295090
return &curbuf->b_ofu_cb;
5091+
49305092
if (*p == 'F')
49315093
{
49325094
if (*++p != ',' && *p != NUL)
49335095
{
4934-
free_callback(&cb);
4935-
slen = copy_option_part(&p, buf, LSIZE, ",");
4936-
if (slen > 0 && option_set_callback_func(buf, &cb))
4937-
return &cb;
4938-
return NULL;
5096+
// 'F{func}' case
5097+
return curbuf->b_p_cpt_cb[idx].cb_name != NULL
5098+
? &curbuf->b_p_cpt_cb[idx] : NULL;
49395099
}
49405100
else
4941-
return &curbuf->b_cfu_cb;
5101+
return &curbuf->b_cfu_cb; // 'cfu'
49425102
}
5103+
49435104
return NULL;
49445105
}
49455106
#endif
@@ -5196,7 +5357,7 @@ prepare_cpt_compl_funcs(void)
51965357
if (*p == NUL)
51975358
break;
51985359

5199-
cb = get_callback_if_cpt_func(p);
5360+
cb = get_callback_if_cpt_func(p, idx);
52005361
if (cb)
52015362
{
52025363
if (get_userdefined_compl_info(curwin->w_cursor.col, cb, &startcol)
@@ -7087,6 +7248,7 @@ free_insexpand_stuff(void)
70877248
free_callback(&cfu_cb);
70887249
free_callback(&ofu_cb);
70897250
free_callback(&tsrfu_cb);
7251+
clear_cpt_callbacks(&cpt_cb, cpt_cb_count);
70907252
# endif
70917253
}
70927254
#endif
@@ -7126,55 +7288,39 @@ setup_cpt_sources(void)
71267288
{
71277289
char_u buf[LSIZE];
71287290
int slen;
7129-
int count = 0, idx = 0;
7130-
char_u *p, *cpt;
7291+
int idx = 0;
7292+
int count;
7293+
char_u *p;
71317294

7132-
// Make a copy of 'cpt' in case the buffer gets wiped out
7133-
cpt = vim_strsave(curbuf->b_p_cpt);
7134-
if (cpt == NULL)
7135-
return FAIL;
7295+
cpt_sources_clear();
71367296

7137-
for (p = cpt; *p;)
7138-
{
7139-
while (*p == ',' || *p == ' ') // Skip delimiters
7140-
p++;
7141-
if (*p) // If not end of string, count this segment
7142-
{
7143-
(void)copy_option_part(&p, buf, LSIZE, ","); // Advance p
7144-
count++;
7145-
}
7146-
}
7297+
count = get_cpt_sources_count();
71477298
if (count == 0)
7148-
goto theend;
7299+
return OK;
71497300

7150-
cpt_sources_clear();
7151-
cpt_sources_count = count;
71527301
cpt_sources_array = ALLOC_CLEAR_MULT(cpt_source_T, count);
71537302
if (cpt_sources_array == NULL)
7154-
{
7155-
cpt_sources_count = 0;
7156-
vim_free(cpt);
71577303
return FAIL;
7158-
}
71597304

7160-
for (p = cpt; *p;)
7305+
for (p = curbuf->b_p_cpt; *p;)
71617306
{
71627307
while (*p == ',' || *p == ' ') // Skip delimiters
71637308
p++;
71647309
if (*p) // If not end of string, count this segment
71657310
{
7166-
char_u *t;
7167-
7168-
vim_memset(buf, 0, LSIZE);
71697311
slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p
7170-
if (slen > 0 && (t = vim_strchr(buf, '^')) != NULL)
7171-
cpt_sources_array[idx].cs_max_matches = atoi((char *)t + 1);
7312+
if (slen > 0)
7313+
{
7314+
char_u *caret = vim_strchr(buf, '^');
7315+
if (caret != NULL)
7316+
cpt_sources_array[idx].cs_max_matches
7317+
= atoi((char *)caret + 1);
7318+
}
71727319
idx++;
71737320
}
71747321
}
71757322

7176-
theend:
7177-
vim_free(cpt);
7323+
cpt_sources_count = count;
71787324
return OK;
71797325
}
71807326

@@ -7335,7 +7481,7 @@ cpt_compl_refresh(void)
73357481

73367482
if (cpt_sources_array[cpt_sources_index].cs_refresh_always)
73377483
{
7338-
cb = get_callback_if_cpt_func(p);
7484+
cb = get_callback_if_cpt_func(p, cpt_sources_index);
73397485
if (cb)
73407486
{
73417487
compl_curr_match = remove_old_matches();

src/option.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7358,6 +7358,9 @@ buf_copy_options(buf_T *buf, int flags)
73587358
}
73597359
buf->b_p_cpt = vim_strsave(p_cpt);
73607360
COPY_OPT_SCTX(buf, BV_CPT);
7361+
#ifdef FEAT_COMPL_FUNC
7362+
set_buflocal_cpt_callbacks(buf);
7363+
#endif
73617364
#ifdef BACKSLASH_IN_FILENAME
73627365
buf->b_p_csl = vim_strsave(p_csl);
73637366
COPY_OPT_SCTX(buf, BV_CSL);

0 commit comments

Comments
 (0)