diff options
-rw-r--r-- | runtime/doc/lua.txt | 2 | ||||
-rw-r--r-- | src/nvim/eval.lua | 3 | ||||
-rw-r--r-- | src/nvim/eval/funcs.h | 1 | ||||
-rw-r--r-- | src/nvim/generators/gen_eval.lua | 7 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 12 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 14 |
6 files changed, 34 insertions, 5 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index b551552c03..dd1843ade3 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1038,6 +1038,8 @@ vim.fn.{func}({...}) *vim.fn* Note: vim.fn keys are generated lazily, thus `pairs(vim.fn)` only enumerates functions that were called at least once. + Note: The majority of functions cannot run in |api-fast| callbacks with some + undocumented exceptions which are allowed. *lua-vim-variables* The Vim editor global dictionaries |g:| |w:| |b:| |t:| |v:| can be accessed diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index d7a17d6e15..3db0d27018 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -10,6 +10,7 @@ -- Defaults to BASE_NONE (function cannot be used as a method). -- func Name of the C function which implements the VimL function. Defaults to -- `f_{funcname}`. +-- fast Function can run in |api-fast| events. Defaults to false. local varargs = function(nr) return {nr} @@ -205,7 +206,7 @@ return { hlID={args=1, base=1}, hlexists={args=1, base=1}, hostname={}, - iconv={args=3, base=1}, + iconv={args=3, base=1, fast=true}, indent={args=1, base=1}, index={args={2, 4}, base=1}, input={args={1, 3}, base=1}, diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h index 4ab4c8f800..5f8d81c989 100644 --- a/src/nvim/eval/funcs.h +++ b/src/nvim/eval/funcs.h @@ -19,6 +19,7 @@ typedef struct { uint8_t min_argc; ///< Minimal number of arguments. uint8_t max_argc; ///< Maximal number of arguments. uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST. + bool fast; ///< Can be run in |api-fast| events VimLFunc func; ///< Function implementation. FunPtr data; ///< Userdata for function implementation. } EvalFuncDef; diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index f094a04c07..c72249161b 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -61,10 +61,11 @@ for _, name in ipairs(neworder) do local base = def.base or "BASE_NONE" local func = def.func or ('f_' .. name) local data = def.data or "NULL" - hashpipe:write((' { "%s", %s, %s, %s, &%s, (FunPtr)%s },\n') - :format(name, args[1], args[2], base, func, data)) + local fast = def.fast and 'true' or 'false' + hashpipe:write((' { "%s", %s, %s, %s, %s, &%s, (FunPtr)%s },\n') + :format(name, args[1], args[2], base, fast, func, data)) end -hashpipe:write(' { NULL, 0, 0, BASE_NONE, NULL, NULL },\n') +hashpipe:write(' { NULL, 0, 0, BASE_NONE, false, NULL, NULL },\n') hashpipe:write("};\n\n") hashpipe:write(hashfun) hashpipe:close() diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9758cee0a5..c2d76e3ce8 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -916,12 +916,22 @@ int nlua_in_fast_event(lua_State *lstate) return 1; } +static bool viml_func_is_fast(const char *name) +{ + const EvalFuncDef *const fdef = find_internal_func((const char *)name); + if (fdef) { + return fdef->fast; + } + // Not a vimL function + return false; +} + int nlua_call(lua_State *lstate) { Error err = ERROR_INIT; size_t name_len; const char *name = luaL_checklstring(lstate, 1, &name_len); - if (!nlua_is_deferred_safe()) { + if (!nlua_is_deferred_safe() && !viml_func_is_fast(name)) { return luaL_error(lstate, e_luv_api_disabled, "vimL function"); } diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 73e4d7ca79..1b9bdd147c 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -794,6 +794,20 @@ describe('lua stdlib', function() pcall_err(exec_lua, "vim.fn.nvim_get_current_line()")) end) + it('vim.fn can be called in fast events (if function is allowed)', function() + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(0, 0, function() + timer:close() + assert(vim.in_fast_event()) + vim.g.fnres = vim.fn.iconv('hello', 'utf-8', 'utf-8') + end) + ]]) + + helpers.poke_eventloop() + eq('hello', exec_lua[[return vim.g.fnres]]) + end) + it('vim.rpcrequest and vim.rpcnotify', function() exec_lua([[ chan = vim.fn.jobstart({'cat'}, {rpc=true}) |