0
0
mirror of https://github.com/vim/vim.git synced 2025-09-27 04:14:06 -04:00

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:
Yegappan Lakshmanan
2021-12-24 20:47:38 +00:00
committed by Bram Moolenaar
parent 73a024209c
commit e7f4abd38b
8 changed files with 84 additions and 39 deletions

View File

@@ -4050,22 +4050,11 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
list_T *list = NULL; list_T *list = NULL;
if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0) 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 // Expand s: and <SID> into <SNR>nr_, so that the function can
// also be called from another script. Using trans_function_name() // also be called from another script. Using trans_function_name()
// would also work, but some plugins depend on the name being // would also work, but some plugins depend on the name being
// printable text. // printable text.
sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid); name = get_scriptlocal_funcname(s);
name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
if (name != NULL)
{
STRCPY(name, sid_buf);
STRCAT(name, s + off);
}
}
else else
name = vim_strsave(s); name = vim_strsave(s);

View File

@@ -4450,7 +4450,18 @@ get_callback(typval_T *arg)
r = FAIL; r = FAIL;
else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) 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; res.cb_name = arg->vval.v_string;
func_ref(res.cb_name); func_ref(res.cb_name);
} }

View File

@@ -7205,33 +7205,8 @@ option_set_callback_func(char_u *optval UNUSED, callback_T *optcb UNUSED)
// Lambda expression or a funcref // Lambda expression or a funcref
tv = eval_expr(optval, NULL); tv = eval_expr(optval, NULL);
else else
{
// treat everything else as a function name string // treat everything else as a function name string
tv = alloc_string_tv(vim_strsave(optval));
// 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) if (tv == NULL)
return FAIL; return FAIL;

View File

@@ -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 *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 *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 *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); char_u *save_function_name(char_u **name, int *is_global, int skip, int flags, funcdict_T *fudi);
void list_functions(regmatch_T *regmatch); void list_functions(regmatch_T *regmatch);
ufunc_T *define_function(exarg_T *eap, char_u *name_arg); ufunc_T *define_function(exarg_T *eap, char_u *name_arg);

View File

@@ -639,6 +639,21 @@ func Test_funcref()
call assert_fails('echo test_null_function()->funcref()', 'E475: Invalid argument: NULL') call assert_fails('echo test_null_function()->funcref()', 'E475: Invalid argument: NULL')
endfunc 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() func Test_setmatches()
let lines =<< trim END let lines =<< trim END
hi def link 1 Comment hi def link 1 Comment

View File

@@ -642,6 +642,18 @@ func Test_opfunc_callback()
END END
call CheckScriptSuccess(lines) 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 " cleanup
set opfunc& set opfunc&
delfunc OpFunc1 delfunc OpFunc1

View File

@@ -3875,6 +3875,46 @@ untrans_function_name(char_u *name)
return NULL; 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. * Call trans_function_name(), except that a lambda is returned as-is.
* Returns the name in allocated memory. * Returns the name in allocated memory.

View File

@@ -749,6 +749,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
3889,
/**/ /**/
3888, 3888,
/**/ /**/