mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
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 vim/vim#9393)
e7f4abd38b
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
@@ -5018,18 +5018,11 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref)
|
||||
int arg_idx = 0;
|
||||
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.
|
||||
snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
|
||||
(int64_t)current_sctx.sc_sid);
|
||||
name = xmalloc(strlen(sid_buf) + strlen(s + off) + 1);
|
||||
STRCPY(name, sid_buf);
|
||||
STRCAT(name, s + off);
|
||||
name = get_scriptlocal_funcname(s);
|
||||
} else {
|
||||
name = xstrdup(s);
|
||||
}
|
||||
@@ -5538,6 +5531,14 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg)
|
||||
callback->type = kCallbackNone;
|
||||
callback->data.funcref = NULL;
|
||||
} else {
|
||||
if (arg->v_type == VAR_STRING) {
|
||||
char *newname = get_scriptlocal_funcname(arg->vval.v_string);
|
||||
if (newname != NULL) {
|
||||
xfree(arg->vval.v_string);
|
||||
name = arg->vval.v_string = newname;
|
||||
}
|
||||
}
|
||||
|
||||
func_ref((char_u *)name);
|
||||
callback->data.funcref = xstrdup(name);
|
||||
callback->type = kCallbackFuncref;
|
||||
|
@@ -1930,6 +1930,40 @@ theend:
|
||||
return (char_u *)name;
|
||||
}
|
||||
|
||||
/// 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 *get_scriptlocal_funcname(char *funcname)
|
||||
{
|
||||
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_usingsid));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char sid_buf[25];
|
||||
// Expand s: and <SID> prefix into <SNR>nr_<name>
|
||||
snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
|
||||
(int64_t)current_sctx.sc_sid);
|
||||
const int off = *funcname == 's' ? 2 : 5;
|
||||
char *newname = xmalloc(strlen(sid_buf) + strlen(funcname + off) + 1);
|
||||
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.
|
||||
char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi)
|
||||
|
@@ -5170,27 +5170,8 @@ int option_set_callback_func(char *optval, Callback *optcb)
|
||||
// treat everything else as a function name string
|
||||
tv = xcalloc(1, sizeof(*tv));
|
||||
tv->v_type = VAR_STRING;
|
||||
|
||||
// Function name starting with "s:" are supported only in a vimscript
|
||||
// context.
|
||||
if (strncmp(optval, "s:", 2) == 0) {
|
||||
char sid_buf[25];
|
||||
|
||||
if (!SCRIPT_ID_VALID(current_sctx.sc_sid)) {
|
||||
emsg(_(e_usingsid));
|
||||
return FAIL;
|
||||
}
|
||||
// Expand s: prefix into <SNR>nr_<name>
|
||||
snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
|
||||
(int64_t)current_sctx.sc_sid);
|
||||
char *funcname = xmalloc(strlen(sid_buf) + strlen(optval + 2) + 1);
|
||||
STRCPY(funcname, sid_buf);
|
||||
STRCAT(funcname, optval + 2);
|
||||
tv->vval.v_string = funcname;
|
||||
} else {
|
||||
tv->vval.v_string = xstrdup(optval);
|
||||
}
|
||||
}
|
||||
|
||||
Callback cb;
|
||||
if (!callback_from_typval(&cb, tv) || cb.type == kCallbackNone) {
|
||||
|
@@ -525,6 +525,21 @@ func Test_funcref()
|
||||
call assert_fails('echo function("min") =~ function("min")', 'E694:')
|
||||
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()
|
||||
hi def link 1 Comment
|
||||
hi def link 2 PreProc
|
||||
|
@@ -658,6 +658,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
|
||||
|
Reference in New Issue
Block a user