diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2021-12-24 20:47:38 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-12-24 20:47:38 +0000 |
commit | e7f4abd38b6e05100c699900c8f87281e363beb2 (patch) | |
tree | badec536bcfe024c7214b18fcce1fa58e5315f80 | |
parent | 73a024209cbfbd5b39a2e974084d807c6131e2ed (diff) | |
download | vim-git-e7f4abd38b6e05100c699900c8f87281e363beb2.tar.gz |
patch 8.2.3889: duplicate code for translating script-local function namev8.2.3889
Problem: Duplicate code for translating script-local function name.
Solution: Move the code to get_scriptlocal_funcname(). (Yegappan Lakshmanan,
closes #9393)
-rw-r--r-- | src/evalfunc.c | 13 | ||||
-rw-r--r-- | src/evalvars.c | 13 | ||||
-rw-r--r-- | src/option.c | 27 | ||||
-rw-r--r-- | src/proto/userfunc.pro | 1 | ||||
-rw-r--r-- | src/testdir/test_expr.vim | 15 | ||||
-rw-r--r-- | src/testdir/test_normal.vim | 12 | ||||
-rw-r--r-- | src/userfunc.c | 40 | ||||
-rw-r--r-- | src/version.c | 2 |
8 files changed, 84 insertions, 39 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c index 778d16d77..8f5205393 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -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); diff --git a/src/evalvars.c b/src/evalvars.c index d002e57b4..34cc014ad 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -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); } diff --git a/src/option.c b/src/option.c index b55789dba..739b29adf 100644 --- a/src/option.c +++ b/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)); - } + tv = alloc_string_tv(vim_strsave(optval)); if (tv == NULL) return FAIL; diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index bb3814352..0320f09d3 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -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); diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index 99cb9a137..ba2e2597a 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -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 diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 08539deb0..57ea6d3ec 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -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 diff --git a/src/userfunc.c b/src/userfunc.c index 7f6754444..897174092 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3876,6 +3876,46 @@ untrans_function_name(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_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. */ diff --git a/src/version.c b/src/version.c index 78baffdec..cd4d15775 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3889, +/**/ 3888, /**/ 3887, |