forked from aniani/vim
patch 8.2.3889: duplicate code for translating script-local function name
Problem: Duplicate code for translating script-local function name. Solution: Move the code to get_scriptlocal_funcname(). (Yegappan Lakshmanan, closes #9393)
This commit is contained in:
committed by
Bram Moolenaar
parent
73a024209c
commit
e7f4abd38b
@@ -4050,22 +4050,11 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
|
||||
list_T *list = NULL;
|
||||
|
||||
if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
|
||||
{
|
||||
char sid_buf[25];
|
||||
int off = *s == 's' ? 2 : 5;
|
||||
|
||||
// Expand s: and <SID> into <SNR>nr_, so that the function can
|
||||
// also be called from another script. Using trans_function_name()
|
||||
// would also work, but some plugins depend on the name being
|
||||
// printable text.
|
||||
sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
|
||||
name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
|
||||
if (name != NULL)
|
||||
{
|
||||
STRCPY(name, sid_buf);
|
||||
STRCAT(name, s + off);
|
||||
}
|
||||
}
|
||||
name = get_scriptlocal_funcname(s);
|
||||
else
|
||||
name = vim_strsave(s);
|
||||
|
||||
|
@@ -4450,7 +4450,18 @@ get_callback(typval_T *arg)
|
||||
r = FAIL;
|
||||
else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
|
||||
{
|
||||
// Note that we don't make a copy of the string.
|
||||
if (arg->v_type == VAR_STRING)
|
||||
{
|
||||
char_u *name;
|
||||
|
||||
name = get_scriptlocal_funcname(arg->vval.v_string);
|
||||
if (name != NULL)
|
||||
{
|
||||
vim_free(arg->vval.v_string);
|
||||
arg->vval.v_string = name;
|
||||
}
|
||||
}
|
||||
|
||||
res.cb_name = arg->vval.v_string;
|
||||
func_ref(res.cb_name);
|
||||
}
|
||||
|
25
src/option.c
25
src/option.c
@@ -7205,33 +7205,8 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
|
||||
// Lambda expression or a funcref
|
||||
tv = eval_expr(optval, NULL);
|
||||
else
|
||||
{
|
||||
// treat everything else as a function name string
|
||||
|
||||
// Function name starting with "s:" are supported only in a vimscript
|
||||
// context.
|
||||
if (STRNCMP(optval, "s:", 2) == 0)
|
||||
{
|
||||
char sid_buf[25];
|
||||
char_u *funcname;
|
||||
|
||||
if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
|
||||
{
|
||||
emsg(_(e_using_sid_not_in_script_context));
|
||||
return FAIL;
|
||||
}
|
||||
// Expand s: prefix into <SNR>nr_<name>
|
||||
sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
|
||||
funcname = alloc(STRLEN(sid_buf) + STRLEN(optval + 2) + 1);
|
||||
if (funcname == NULL)
|
||||
return FAIL;
|
||||
STRCPY(funcname, sid_buf);
|
||||
STRCAT(funcname, optval + 2);
|
||||
tv = alloc_string_tv(funcname);
|
||||
}
|
||||
else
|
||||
tv = alloc_string_tv(vim_strsave(optval));
|
||||
}
|
||||
if (tv == NULL)
|
||||
return FAIL;
|
||||
|
||||
|
@@ -35,6 +35,7 @@ int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typva
|
||||
char_u *printable_func_name(ufunc_T *fp);
|
||||
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial, type_T **type);
|
||||
char_u *untrans_function_name(char_u *name);
|
||||
char_u *get_scriptlocal_funcname(char_u *funcname);
|
||||
char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi);
|
||||
void list_functions(regmatch_T *regmatch);
|
||||
ufunc_T *define_function(exarg_T *eap, char_u *name_arg);
|
||||
|
@@ -639,6 +639,21 @@ func Test_funcref()
|
||||
call assert_fails('echo test_null_function()->funcref()', 'E475: Invalid argument: NULL')
|
||||
endfunc
|
||||
|
||||
" Test for calling function() and funcref() outside of a Vim script context.
|
||||
func Test_function_outside_script()
|
||||
let cleanup =<< trim END
|
||||
call writefile([execute('messages')], 'Xtest.out')
|
||||
qall
|
||||
END
|
||||
call writefile(cleanup, 'Xverify.vim')
|
||||
call RunVim([], [], "-c \"echo function('s:abc')\" -S Xverify.vim")
|
||||
call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
|
||||
call RunVim([], [], "-c \"echo funcref('s:abc')\" -S Xverify.vim")
|
||||
call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
|
||||
call delete('Xtest.out')
|
||||
call delete('Xverify.vim')
|
||||
endfunc
|
||||
|
||||
func Test_setmatches()
|
||||
let lines =<< trim END
|
||||
hi def link 1 Comment
|
||||
|
@@ -642,6 +642,18 @@ func Test_opfunc_callback()
|
||||
END
|
||||
call CheckScriptSuccess(lines)
|
||||
|
||||
" setting 'opfunc' to a script local function outside of a script context
|
||||
" should fail
|
||||
let cleanup =<< trim END
|
||||
call writefile([execute('messages')], 'Xtest.out')
|
||||
qall
|
||||
END
|
||||
call writefile(cleanup, 'Xverify.vim')
|
||||
call RunVim([], [], "-c \"set opfunc=s:abc\" -S Xverify.vim")
|
||||
call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
|
||||
call delete('Xtest.out')
|
||||
call delete('Xverify.vim')
|
||||
|
||||
" cleanup
|
||||
set opfunc&
|
||||
delfunc OpFunc1
|
||||
|
@@ -3875,6 +3875,46 @@ untrans_function_name(char_u *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the 'funcname' starts with "s:" or "<SID>", then expands it to the
|
||||
* current script ID and returns the expanded function name. The caller should
|
||||
* free the returned name. If not called from a script context or the function
|
||||
* name doesn't start with these prefixes, then returns NULL.
|
||||
* This doesn't check whether the script-local function exists or not.
|
||||
*/
|
||||
char_u *
|
||||
get_scriptlocal_funcname(char_u *funcname)
|
||||
{
|
||||
char sid_buf[25];
|
||||
int off;
|
||||
char_u *newname;
|
||||
|
||||
if (funcname == NULL)
|
||||
return NULL;
|
||||
|
||||
if (STRNCMP(funcname, "s:", 2) != 0
|
||||
&& STRNCMP(funcname, "<SID>", 5) != 0)
|
||||
// The function name is not a script-local function name
|
||||
return NULL;
|
||||
|
||||
if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
|
||||
{
|
||||
emsg(_(e_using_sid_not_in_script_context));
|
||||
return NULL;
|
||||
}
|
||||
// Expand s: prefix into <SNR>nr_<name>
|
||||
vim_snprintf(sid_buf, sizeof(sid_buf), "<SNR>%ld_",
|
||||
(long)current_sctx.sc_sid);
|
||||
off = *funcname == 's' ? 2 : 5;
|
||||
newname = alloc(STRLEN(sid_buf) + STRLEN(funcname + off) + 1);
|
||||
if (newname == NULL)
|
||||
return NULL;
|
||||
STRCPY(newname, sid_buf);
|
||||
STRCAT(newname, funcname + off);
|
||||
|
||||
return newname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call trans_function_name(), except that a lambda is returned as-is.
|
||||
* Returns the name in allocated memory.
|
||||
|
@@ -749,6 +749,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
3889,
|
||||
/**/
|
||||
3888,
|
||||
/**/
|
||||
|
Reference in New Issue
Block a user