aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-12-03 04:26:00 +0800
committerGitHub <noreply@github.com>2022-12-03 04:26:00 +0800
commit10c50d9f30138e7811789ba1c62f4c520cf04c8f (patch)
tree6be3628f7d152c1f703f59fa1050039c90244707 /src
parent07e6296520fc83b1fdb287b5173494cdd0e9136f (diff)
parentafb3ff52ecafe2d5bd1239869124794bb2ac68b9 (diff)
downloadrneovim-10c50d9f30138e7811789ba1c62f4c520cf04c8f.tar.gz
rneovim-10c50d9f30138e7811789ba1c62f4c520cf04c8f.tar.bz2
rneovim-10c50d9f30138e7811789ba1c62f4c520cf04c8f.zip
Merge pull request #21266 from zeertzjq/vim-8.2.3889
vim-patch:8.2.3889,9.0.{0805,0990}
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c20
-rw-r--r--src/nvim/eval/userfunc.c34
-rw-r--r--src/nvim/option.c21
-rw-r--r--src/nvim/quickfix.c6
-rw-r--r--src/nvim/testdir/test_expr.vim15
-rw-r--r--src/nvim/testdir/test_normal.vim12
-rw-r--r--src/nvim/testdir/test_quickfix.vim28
7 files changed, 106 insertions, 30 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index c4afd6934c..6d8f4d092c 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -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);
}
@@ -5517,6 +5510,7 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool retlist
}
}
+/// Get a callback from "arg". It can be a Funcref or a function name.
bool callback_from_typval(Callback *const callback, typval_T *const arg)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -5538,8 +5532,14 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg)
callback->type = kCallbackNone;
callback->data.funcref = NULL;
} else {
- func_ref((char_u *)name);
- callback->data.funcref = xstrdup(name);
+ callback->data.funcref = NULL;
+ if (arg->v_type == VAR_STRING) {
+ callback->data.funcref = get_scriptlocal_funcname(name);
+ }
+ if (callback->data.funcref == NULL) {
+ callback->data.funcref = xstrdup(name);
+ }
+ func_ref((char_u *)callback->data.funcref);
callback->type = kCallbackFuncref;
}
} else if (nlua_is_table_from_lua(arg)) {
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 359ce08554..a37613dca9 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -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)
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 6d461d9b9d..e67bacce61 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -5170,26 +5170,7 @@ 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);
- }
+ tv->vval.v_string = xstrdup(optval);
}
Callback cb;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index deac0bb8a1..d4dff746c7 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3900,6 +3900,9 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
qf_winid = (int)win->handle;
}
+ // autocommands may cause trouble
+ incr_quickfix_busy();
+
aco_save_T aco;
if (old_last == NULL) {
@@ -3924,6 +3927,9 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) {
redraw_buf_later(buf, UPD_NOT_VALID);
}
+
+ // always called after incr_quickfix_busy()
+ decr_quickfix_busy();
}
}
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index f33358c59a..47f7f5eb0e 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -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
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index d9b392992f..9c5cc51f79 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -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
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 02cee8a8dd..7b94c4027c 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -3298,6 +3298,21 @@ func Test_resize_from_copen()
endtry
endfunc
+func Test_filetype_autocmd()
+ " this changes the location list while it is in use to fill a buffer
+ lexpr ''
+ lopen
+ augroup FT_loclist
+ au FileType * call setloclist(0, [], 'f')
+ augroup END
+ silent! lolder
+ lexpr ''
+
+ augroup FT_loclist
+ au! FileType
+ augroup END
+endfunc
+
func Test_vimgrep_with_textlock()
new
@@ -6165,4 +6180,17 @@ func Test_loclist_replace_autocmd()
call setloclist(0, [], 'f')
endfunc
+func s:QfTf(_)
+endfunc
+
+func Test_setqflist_cb_arg()
+ " This was changing the callback name in the dictionary.
+ let d = #{quickfixtextfunc: 's:QfTf'}
+ call setqflist([], 'a', d)
+ call assert_equal('s:QfTf', d.quickfixtextfunc)
+
+ call setqflist([], 'f')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab