Mercurial > vim
diff src/eval.c @ 8538:c337c813c64d v7.4.1559
commit https://github.com/vim/vim/commit/1735bc988c546cc962c5f94792815b4d7cb79710
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Mar 14 23:05:14 2016 +0100
patch 7.4.1559
Problem: Passing cookie to a callback is clumsy.
Solution: Change function() to take arguments and return a partial.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 14 Mar 2016 23:15:05 +0100 |
parents | 09041d2fd7d0 |
children | 24db3583c496 |
line wrap: on
line diff
--- a/src/eval.c +++ b/src/eval.c @@ -452,8 +452,8 @@ static char_u *tv2string(typval_T *tv, c static char_u *string_quote(char_u *str, int function); static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate); static int find_internal_func(char_u *name); -static char_u *deref_func_name(char_u *name, int *lenp, int no_autoload); -static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict); +static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload); +static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict); static void emsg_funcname(char *ermsg, char_u *name); static int non_zero_arg(typval_T *argvars); @@ -1675,7 +1675,7 @@ call_vim_function( rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &doesrange, TRUE, NULL); + &doesrange, TRUE, NULL, NULL); if (safe) { --sandbox; @@ -3091,6 +3091,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char case VAR_UNKNOWN: case VAR_DICT: case VAR_FUNC: + case VAR_PARTIAL: case VAR_SPECIAL: case VAR_JOB: case VAR_CHANNEL: @@ -3456,6 +3457,7 @@ ex_call(exarg_T *eap) int doesrange; int failed = FALSE; funcdict_T fudi; + partial_T *partial; if (eap->skip) { @@ -3486,7 +3488,7 @@ ex_call(exarg_T *eap) /* If it is the name of a variable of type VAR_FUNC use its contents. */ len = (int)STRLEN(tofree); - name = deref_func_name(tofree, &len, FALSE); + name = deref_func_name(tofree, &len, &partial, FALSE); /* Skip white space to allow ":call func ()". Not good, but required for * backward compatibility. */ @@ -3525,7 +3527,7 @@ ex_call(exarg_T *eap) arg = startarg; if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg, eap->line1, eap->line2, &doesrange, - !eap->skip, fudi.fd_dict) == FAIL) + !eap->skip, partial, fudi.fd_dict) == FAIL) { failed = TRUE; break; @@ -3870,6 +3872,7 @@ item_lock(typval_T *tv, int deep, int lo case VAR_NUMBER: case VAR_STRING: case VAR_FUNC: + case VAR_PARTIAL: case VAR_FLOAT: case VAR_SPECIAL: case VAR_JOB: @@ -4542,7 +4545,8 @@ eval4(char_u **arg, typval_T *rettv, int } } - else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC) + else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC + || rettv->v_type == VAR_PARTIAL || var2.v_type == VAR_PARTIAL) { if (rettv->v_type != var2.v_type || (type != TYPE_EQUAL && type != TYPE_NEQUAL)) @@ -4555,6 +4559,12 @@ eval4(char_u **arg, typval_T *rettv, int clear_tv(&var2); return FAIL; } + else if (rettv->v_type == VAR_PARTIAL) + { + /* Partials are only equal when identical. */ + n1 = rettv->vval.v_partial != NULL + && rettv->vval.v_partial == var2.vval.v_partial; + } else { /* Compare two Funcrefs for being equal or unequal. */ @@ -4564,9 +4574,9 @@ eval4(char_u **arg, typval_T *rettv, int else n1 = STRCMP(rettv->vval.v_string, var2.vval.v_string) == 0; - if (type == TYPE_NEQUAL) - n1 = !n1; - } + } + if (type == TYPE_NEQUAL) + n1 = !n1; } #ifdef FEAT_FLOAT @@ -5230,14 +5240,16 @@ eval7( { if (**arg == '(') /* recursive! */ { + partial_T *partial; + /* If "s" is the name of a variable of type VAR_FUNC * use its contents. */ - s = deref_func_name(s, &len, !evaluate); + s = deref_func_name(s, &len, &partial, !evaluate); /* Invoke the function. */ ret = get_func_tv(s, len, rettv, arg, curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &len, evaluate, NULL); + &len, evaluate, partial, NULL); /* If evaluate is FALSE rettv->v_type was not set in * get_func_tv, but it's needed in handle_subscript() to parse @@ -5359,6 +5371,7 @@ eval_index( switch (rettv->v_type) { case VAR_FUNC: + case VAR_PARTIAL: if (verbose) EMSG(_("E695: Cannot index a Funcref")); return FAIL; @@ -5480,6 +5493,7 @@ eval_index( { case VAR_UNKNOWN: case VAR_FUNC: + case VAR_PARTIAL: case VAR_FLOAT: case VAR_SPECIAL: case VAR_JOB: @@ -6218,6 +6232,10 @@ tv_equal( && tv2->vval.v_string != NULL && STRCMP(tv1->vval.v_string, tv2->vval.v_string) == 0); + case VAR_PARTIAL: + return tv1->vval.v_partial != NULL + && tv1->vval.v_partial == tv2->vval.v_partial; + case VAR_NUMBER: return tv1->vval.v_number == tv2->vval.v_number; @@ -7793,6 +7811,12 @@ echo_string( r = tv->vval.v_string; break; + case VAR_PARTIAL: + *tofree = NULL; + /* TODO: arguments */ + r = tv->vval.v_partial == NULL ? NULL : tv->vval.v_partial->pt_name; + break; + case VAR_LIST: if (tv->vval.v_list == NULL) { @@ -7878,6 +7902,10 @@ tv2string( case VAR_FUNC: *tofree = string_quote(tv->vval.v_string, TRUE); return *tofree; + case VAR_PARTIAL: + *tofree = string_quote(tv->vval.v_partial == NULL ? NULL + : tv->vval.v_partial->pt_name, TRUE); + return *tofree; case VAR_STRING: *tofree = string_quote(tv->vval.v_string, FALSE); return *tofree; @@ -8146,7 +8174,7 @@ static struct fst {"foldtext", 0, 0, f_foldtext}, {"foldtextresult", 1, 1, f_foldtextresult}, {"foreground", 0, 0, f_foreground}, - {"function", 1, 1, f_function}, + {"function", 1, 3, f_function}, {"garbagecollect", 0, 1, f_garbagecollect}, {"get", 2, 3, f_get}, {"getbufline", 2, 3, f_getbufline}, @@ -8524,13 +8552,16 @@ find_internal_func( /* * Check if "name" is a variable of type VAR_FUNC. If so, return the function * name it contains, otherwise return "name". + * If "name" is of type VAR_PARTIAL also return "partial" */ static char_u * -deref_func_name(char_u *name, int *lenp, int no_autoload) +deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload) { dictitem_T *v; int cc; + *partial = NULL; + cc = name[*lenp]; name[*lenp] = NUL; v = find_var(name, NULL, no_autoload); @@ -8546,6 +8577,18 @@ deref_func_name(char_u *name, int *lenp, return v->di_tv.vval.v_string; } + if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) + { + *partial = v->di_tv.vval.v_partial; + if (*partial == NULL) + { + *lenp = 0; + return (char_u *)""; /* just in case */ + } + *lenp = (int)STRLEN((*partial)->pt_name); + return (*partial)->pt_name; + } + return name; } @@ -8563,6 +8606,7 @@ get_func_tv( linenr_T lastline, /* last line of range */ int *doesrange, /* return: function handled range */ int evaluate, + partial_T *partial, /* for extra arguments */ dict_T *selfdict) /* Dictionary for "self" */ { char_u *argp; @@ -8574,7 +8618,7 @@ get_func_tv( * Get the arguments. */ argp = *arg; - while (argcount < MAX_FUNC_ARGS) + while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) { argp = skipwhite(argp + 1); /* skip the '(' or ',' */ if (*argp == ')' || *argp == ',' || *argp == NUL) @@ -8595,7 +8639,7 @@ get_func_tv( if (ret == OK) ret = call_func(name, len, rettv, argcount, argvars, - firstline, lastline, doesrange, evaluate, selfdict); + firstline, lastline, doesrange, evaluate, partial, selfdict); else if (!aborting()) { if (argcount == MAX_FUNC_ARGS) @@ -8622,14 +8666,15 @@ call_func( char_u *funcname, /* name of the function */ int len, /* length of "name" */ typval_T *rettv, /* return value goes here */ - int argcount, /* number of "argvars" */ - typval_T *argvars, /* vars for arguments, must have "argcount" + int argcount_in, /* number of "argvars" */ + typval_T *argvars_in, /* vars for arguments, must have "argcount" PLUS ONE elements! */ linenr_T firstline, /* first line of range */ linenr_T lastline, /* last line of range */ int *doesrange, /* return: function handled range */ int evaluate, - dict_T *selfdict) /* Dictionary for "self" */ + partial_T *partial, /* optional, can be NULL */ + dict_T *selfdict_in) /* Dictionary for "self" */ { int ret = FAIL; #define ERROR_UNKNOWN 0 @@ -8639,6 +8684,7 @@ call_func( #define ERROR_DICT 4 #define ERROR_NONE 5 #define ERROR_OTHER 6 +#define ERROR_BOTH 7 int error = ERROR_NONE; int i; int llen; @@ -8647,6 +8693,11 @@ call_func( char_u fname_buf[FLEN_FIXED + 1]; char_u *fname; char_u *name; + int argcount = argcount_in; + typval_T *argvars = argvars_in; + dict_T *selfdict = selfdict_in; + typval_T argv[MAX_FUNC_ARGS + 1]; /* used when "partial" is not NULL */ + int argv_clear = 0; /* Make a copy of the name, if it comes from a funcref variable it could * be changed or deleted in the called function. */ @@ -8698,6 +8749,27 @@ call_func( *doesrange = FALSE; + if (partial != NULL) + { + if (partial->pt_dict != NULL) + { + if (selfdict_in != NULL) + error = ERROR_BOTH; + selfdict = partial->pt_dict; + } + if (error == ERROR_NONE && partial->pt_argc > 0) + { + int i; + + for (argv_clear = 0; argv_clear < partial->pt_argc; ++argv_clear) + copy_tv(&partial->pt_argv[argv_clear], &argv[argv_clear]); + for (i = 0; i < argcount_in; ++i) + argv[i + argv_clear] = argvars_in[i]; + argvars = argv; + argcount = partial->pt_argc + argcount_in; + } + } + /* execute the function if no errors detected and executing */ if (evaluate && error == ERROR_NONE) @@ -8841,9 +8913,15 @@ call_func( emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"), name); break; - } - } - + case ERROR_BOTH: + emsg_funcname(N_("E924: can't have both a \"self\" dict and a partial: %s"), + name); + break; + } + } + + while (argv_clear > 0) + clear_tv(&argv[--argv_clear]); if (fname != name && fname != fname_buf) vim_free(fname); vim_free(name); @@ -9737,6 +9815,7 @@ f_byteidxcomp(typval_T *argvars, typval_ func_call( char_u *name, typval_T *args, + partial_T *partial, dict_T *selfdict, typval_T *rettv) { @@ -9749,7 +9828,7 @@ func_call( for (item = args->vval.v_list->lv_first; item != NULL; item = item->li_next) { - if (argc == MAX_FUNC_ARGS) + if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) { EMSG(_("E699: Too many arguments")); break; @@ -9763,7 +9842,7 @@ func_call( if (item == NULL) r = call_func(name, (int)STRLEN(name), rettv, argc, argv, curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &dummy, TRUE, selfdict); + &dummy, TRUE, partial, selfdict); /* Free the arguments. */ while (argc > 0) @@ -9773,12 +9852,13 @@ func_call( } /* - * "call(func, arglist)" function + * "call(func, arglist [, dict])" function */ static void f_call(typval_T *argvars, typval_T *rettv) { char_u *func; + partial_T *partial = NULL; dict_T *selfdict = NULL; if (argvars[1].v_type != VAR_LIST) @@ -9791,6 +9871,11 @@ f_call(typval_T *argvars, typval_T *rett if (argvars[0].v_type == VAR_FUNC) func = argvars[0].vval.v_string; + else if (argvars[0].v_type == VAR_PARTIAL) + { + partial = argvars[0].vval.v_partial; + func = partial->pt_name; + } else func = get_tv_string(&argvars[0]); if (*func == NUL) @@ -9806,7 +9891,7 @@ f_call(typval_T *argvars, typval_T *rett selfdict = argvars[2].vval.v_dict; } - (void)func_call(func, &argvars[1], selfdict, rettv); + (void)func_call(func, &argvars[1], partial, selfdict, rettv); } #ifdef FEAT_FLOAT @@ -10627,6 +10712,9 @@ f_empty(typval_T *argvars, typval_T *ret n = argvars[0].vval.v_string == NULL || *argvars[0].vval.v_string == NUL; break; + case VAR_PARTIAL: + n = FALSE; + break; case VAR_NUMBER: n = argvars[0].vval.v_number == 0; break; @@ -11688,6 +11776,7 @@ f_foreground(typval_T *argvars UNUSED, t f_function(typval_T *argvars, typval_T *rettv) { char_u *s; + char_u *name; s = get_tv_string(&argvars[0]); if (s == NULL || *s == NUL || VIM_ISDIGIT(*s)) @@ -11707,18 +11796,118 @@ f_function(typval_T *argvars, typval_T * * would also work, but some plugins depend on the name being * printable text. */ sprintf(sid_buf, "<SNR>%ld_", (long)current_SID); - rettv->vval.v_string = - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); - if (rettv->vval.v_string != NULL) - { - STRCPY(rettv->vval.v_string, sid_buf); - STRCAT(rettv->vval.v_string, s + off); - } - } - else - rettv->vval.v_string = vim_strsave(s); - rettv->v_type = VAR_FUNC; - } + name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1)); + if (name != NULL) + { + STRCPY(name, sid_buf); + STRCAT(name, s + off); + } + } + else + name = vim_strsave(s); + + if (argvars[1].v_type != VAR_UNKNOWN) + { + partial_T *pt; + int dict_idx = 0; + int arg_idx = 0; + + if (argvars[2].v_type != VAR_UNKNOWN) + { + /* function(name, [args], dict) */ + arg_idx = 1; + dict_idx = 2; + } + else if (argvars[1].v_type == VAR_DICT) + /* function(name, dict) */ + dict_idx = 1; + else + /* function(name, [args]) */ + arg_idx = 1; + if (dict_idx > 0 && (argvars[dict_idx].v_type != VAR_DICT + || argvars[dict_idx].vval.v_dict == NULL)) + { + EMSG(_("E922: expected a dict")); + vim_free(name); + return; + } + if (arg_idx > 0 && (argvars[arg_idx].v_type != VAR_LIST + || argvars[arg_idx].vval.v_list == NULL)) + { + EMSG(_("E923: Second argument of function() must be a list or a dict")); + vim_free(name); + return; + } + + pt = (partial_T *)alloc_clear(sizeof(partial_T)); + if (pt != NULL) + { + if (arg_idx > 0) + { + list_T *list = argvars[arg_idx].vval.v_list; + listitem_T *li; + int i = 0; + + pt->pt_argv = (typval_T *)alloc( + sizeof(typval_T) * list->lv_len); + if (pt->pt_argv == NULL) + { + vim_free(pt); + vim_free(name); + return; + } + else + { + pt->pt_argc = list->lv_len; + for (li = list->lv_first; li != NULL; li = li->li_next) + copy_tv(&li->li_tv, &pt->pt_argv[i++]); + } + } + + if (dict_idx > 0) + { + pt->pt_dict = argvars[dict_idx].vval.v_dict; + ++pt->pt_dict->dv_refcount; + } + + pt->pt_refcount = 1; + pt->pt_name = name; + func_ref(pt->pt_name); + } + rettv->v_type = VAR_PARTIAL; + rettv->vval.v_partial = pt; + } + else + { + rettv->v_type = VAR_FUNC; + rettv->vval.v_string = name; + func_ref(name); + } + } +} + + static void +partial_free(partial_T *pt) +{ + int i; + + for (i = 0; i < pt->pt_argc; ++i) + clear_tv(&pt->pt_argv[i]); + vim_free(pt->pt_argv); + func_unref(pt->pt_name); + vim_free(pt->pt_name); + vim_free(pt); +} + +/* + * Unreference a closure: decrement the reference count and free it when it + * becomes zero. + */ + void +partial_unref(partial_T *pt) +{ + if (pt != NULL && --pt->pt_refcount <= 0) + partial_free(pt); } /* @@ -14598,6 +14787,7 @@ f_len(typval_T *argvars, typval_T *rettv case VAR_SPECIAL: case VAR_FLOAT: case VAR_FUNC: + case VAR_PARTIAL: case VAR_JOB: case VAR_CHANNEL: EMSG(_("E701: Invalid type for len()")); @@ -18169,6 +18359,7 @@ typedef struct int item_compare_float; #endif char_u *item_compare_func; + partial_T *item_compare_partial; dict_T *item_compare_selfdict; int item_compare_func_err; int item_compare_keep_zero; @@ -18278,6 +18469,8 @@ item_compare2(const void *s1, const void typval_T rettv; typval_T argv[3]; int dummy; + char_u *func_name; + partial_T *partial = sortinfo->item_compare_partial; /* shortcut after failure in previous call; compare all items equal */ if (sortinfo->item_compare_func_err) @@ -18286,16 +18479,20 @@ item_compare2(const void *s1, const void si1 = (sortItem_T *)s1; si2 = (sortItem_T *)s2; + if (partial == NULL) + func_name = sortinfo->item_compare_func; + else + func_name = partial->pt_name; + /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED * in the copy without changing the original list items. */ copy_tv(&si1->item->li_tv, &argv[0]); copy_tv(&si2->item->li_tv, &argv[1]); rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */ - res = call_func(sortinfo->item_compare_func, - (int)STRLEN(sortinfo->item_compare_func), + res = call_func(func_name, (int)STRLEN(func_name), &rettv, 2, argv, 0L, 0L, &dummy, TRUE, - sortinfo->item_compare_selfdict); + partial, sortinfo->item_compare_selfdict); clear_tv(&argv[0]); clear_tv(&argv[1]); @@ -18358,12 +18555,15 @@ do_sort_uniq(typval_T *argvars, typval_T info.item_compare_float = FALSE; #endif info.item_compare_func = NULL; + info.item_compare_partial = NULL; info.item_compare_selfdict = NULL; if (argvars[1].v_type != VAR_UNKNOWN) { /* optional second argument: {func} */ if (argvars[1].v_type == VAR_FUNC) info.item_compare_func = argvars[1].vval.v_string; + else if (argvars[1].v_type == VAR_PARTIAL) + info.item_compare_partial = argvars[1].vval.v_partial; else { int error = FALSE; @@ -18443,7 +18643,8 @@ do_sort_uniq(typval_T *argvars, typval_T info.item_compare_func_err = FALSE; info.item_compare_keep_zero = FALSE; /* test the compare function */ - if (info.item_compare_func != NULL + if ((info.item_compare_func != NULL + || info.item_compare_partial != NULL) && item_compare2((void *)&ptrs[0], (void *)&ptrs[1]) == ITEM_COMPARE_FAIL) EMSG(_("E702: Sort compare function failed")); @@ -18452,6 +18653,7 @@ do_sort_uniq(typval_T *argvars, typval_T /* Sort the array with item pointers. */ qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T), info.item_compare_func == NULL + && info.item_compare_partial == NULL ? item_compare : item_compare2); if (!info.item_compare_func_err) @@ -18471,7 +18673,8 @@ do_sort_uniq(typval_T *argvars, typval_T /* f_uniq(): ptrs will be a stack of items to remove */ info.item_compare_func_err = FALSE; info.item_compare_keep_zero = TRUE; - item_compare_func_ptr = info.item_compare_func + item_compare_func_ptr = info.item_compare_func != NULL + || info.item_compare_partial != NULL ? item_compare2 : item_compare; for (li = l->lv_first; li != NULL && li->li_next != NULL; @@ -20045,6 +20248,7 @@ f_type(typval_T *argvars, typval_T *rett break; case VAR_JOB: n = 8; break; case VAR_CHANNEL: n = 9; break; + case VAR_PARTIAL: n = 10; break; case VAR_UNKNOWN: EMSG2(_(e_intern2), "f_type(UNKNOWN)"); n = -1; @@ -21295,11 +21499,13 @@ handle_subscript( char_u *s; int len; typval_T functv; + partial_T *pt = NULL; while (ret == OK && (**arg == '[' || (**arg == '.' && rettv->v_type == VAR_DICT) - || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC))) + || (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC + || rettv->v_type == VAR_PARTIAL))) && !vim_iswhite(*(*arg - 1))) { if (**arg == '(') @@ -21311,13 +21517,19 @@ handle_subscript( rettv->v_type = VAR_UNKNOWN; /* Invoke the function. Recursive! */ - s = functv.vval.v_string; + if (rettv->v_type == VAR_PARTIAL) + { + pt = functv.vval.v_partial; + s = pt->pt_name; + } + else + s = functv.vval.v_string; } else s = (char_u *)""; ret = get_func_tv(s, (int)STRLEN(s), rettv, arg, curwin->w_cursor.lnum, curwin->w_cursor.lnum, - &len, evaluate, selfdict); + &len, evaluate, pt, selfdict); /* Clear the funcref afterwards, so that deleting it while * evaluating the arguments is possible (see test55). */ @@ -21405,6 +21617,9 @@ free_tv(typval_T *varp) case VAR_STRING: vim_free(varp->vval.v_string); break; + case VAR_PARTIAL: + partial_unref(varp->vval.v_partial); + break; case VAR_LIST: list_unref(varp->vval.v_list); break; @@ -21448,6 +21663,10 @@ clear_tv(typval_T *varp) vim_free(varp->vval.v_string); varp->vval.v_string = NULL; break; + case VAR_PARTIAL: + partial_unref(varp->vval.v_partial); + varp->vval.v_partial = NULL; + break; case VAR_LIST: list_unref(varp->vval.v_list); varp->vval.v_list = NULL; @@ -21524,6 +21743,7 @@ get_tv_number_chk(typval_T *varp, int *d break; #endif case VAR_FUNC: + case VAR_PARTIAL: EMSG(_("E703: Using a Funcref as a Number")); break; case VAR_STRING: @@ -21572,6 +21792,7 @@ get_tv_float(typval_T *varp) case VAR_FLOAT: return varp->vval.v_float; case VAR_FUNC: + case VAR_PARTIAL: EMSG(_("E891: Using a Funcref as a Float")); break; case VAR_STRING: @@ -21688,6 +21909,7 @@ get_tv_string_buf_chk(typval_T *varp, ch sprintf((char *)buf, "%ld", (long)varp->vval.v_number); return buf; case VAR_FUNC: + case VAR_PARTIAL: EMSG(_("E729: using Funcref as a String")); break; case VAR_LIST: @@ -22087,7 +22309,7 @@ list_one_var_a( msg_advance(22); if (type == VAR_NUMBER) msg_putchar('#'); - else if (type == VAR_FUNC) + else if (type == VAR_FUNC || type == VAR_PARTIAL) msg_putchar('*'); else if (type == VAR_LIST) { @@ -22106,7 +22328,7 @@ list_one_var_a( msg_outtrans(string); - if (type == VAR_FUNC) + if (type == VAR_FUNC || type == VAR_PARTIAL) msg_puts((char_u *)"()"); if (*first) { @@ -22138,7 +22360,8 @@ set_var( } v = find_var_in_ht(ht, 0, varname, TRUE); - if (tv->v_type == VAR_FUNC && var_check_func_name(name, v == NULL)) + if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) + && var_check_func_name(name, v == NULL)) return; if (v != NULL) @@ -22383,6 +22606,15 @@ copy_tv(typval_T *from, typval_T *to) func_ref(to->vval.v_string); } break; + case VAR_PARTIAL: + if (from->vval.v_partial == NULL) + to->vval.v_partial = NULL; + else + { + to->vval.v_partial = from->vval.v_partial; + ++to->vval.v_partial->pt_refcount; + } + break; case VAR_LIST: if (from->vval.v_list == NULL) to->vval.v_list = NULL; @@ -22437,6 +22669,7 @@ item_copy( case VAR_FLOAT: case VAR_STRING: case VAR_FUNC: + case VAR_PARTIAL: case VAR_SPECIAL: case VAR_JOB: case VAR_CHANNEL: @@ -23415,6 +23648,7 @@ trans_function_name( char_u sid_buf[20]; int len; lval_T lv; + partial_T *partial; if (fdp != NULL) vim_memset(fdp, 0, sizeof(funcdict_T)); @@ -23499,14 +23733,15 @@ trans_function_name( if (lv.ll_exp_name != NULL) { len = (int)STRLEN(lv.ll_exp_name); - name = deref_func_name(lv.ll_exp_name, &len, flags & TFN_NO_AUTOLOAD); + name = deref_func_name(lv.ll_exp_name, &len, &partial, + flags & TFN_NO_AUTOLOAD); if (name == lv.ll_exp_name) name = NULL; } else { len = (int)(end - *pp); - name = deref_func_name(*pp, &len, flags & TFN_NO_AUTOLOAD); + name = deref_func_name(*pp, &len, &partial, flags & TFN_NO_AUTOLOAD); if (name == *pp) name = NULL; } @@ -25111,6 +25346,7 @@ write_viminfo_varlist(FILE *fp) case VAR_UNKNOWN: case VAR_FUNC: + case VAR_PARTIAL: case VAR_JOB: case VAR_CHANNEL: continue;