mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge pull request #6704 from bfredl/luaexec
execute lua directly from the remote API
This commit is contained in:
		| @@ -68,9 +68,9 @@ set(NVIM_VERSION_PATCH 1) | ||||
| set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers | ||||
|  | ||||
| # API level | ||||
| set(NVIM_API_LEVEL 2)         # Bump this after any API change. | ||||
| set(NVIM_API_LEVEL 3)         # Bump this after any API change. | ||||
| set(NVIM_API_LEVEL_COMPAT 0)  # Adjust this after a _breaking_ API change. | ||||
| set(NVIM_API_PRERELEASE false) | ||||
| set(NVIM_API_PRERELEASE true) | ||||
|  | ||||
| file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR) | ||||
| include(GetGitRevisionDescription) | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| #include "nvim/api/private/defs.h" | ||||
| #include "nvim/api/buffer.h" | ||||
| #include "nvim/msgpack_rpc/channel.h" | ||||
| #include "nvim/lua/executor.h" | ||||
| #include "nvim/vim.h" | ||||
| #include "nvim/buffer.h" | ||||
| #include "nvim/file_search.h" | ||||
| @@ -254,6 +255,25 @@ free_vim_args: | ||||
|   return rv; | ||||
| } | ||||
|  | ||||
| /// Execute lua code. Parameters might be passed, they are available inside | ||||
| /// the chunk as `...`. The chunk can return a value. | ||||
| /// | ||||
| /// To evaluate an expression, it must be prefixed with "return ". For | ||||
| /// instance, to call a lua function with arguments sent in and get its | ||||
| /// return value back, use the code "return my_function(...)". | ||||
| /// | ||||
| /// @param code       lua code to execute | ||||
| /// @param args       Arguments to the code | ||||
| /// @param[out] err   Details of an error encountered while parsing | ||||
| ///                   or executing the lua code. | ||||
| /// | ||||
| /// @return           Return value of lua code if present or NIL. | ||||
| Object nvim_execute_lua(String code, Array args, Error *err) | ||||
|   FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY | ||||
| { | ||||
|   return executor_exec_lua_api(code, args, err); | ||||
| } | ||||
|  | ||||
| /// Calculates the number of display cells occupied by `text`. | ||||
| /// <Tab> counts as one cell. | ||||
| /// | ||||
|   | ||||
| @@ -373,6 +373,46 @@ static int nlua_eval_lua_string(lua_State *const lstate) | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /// Evaluate lua string | ||||
| /// | ||||
| /// Expects four values on the stack: string to evaluate, pointer to args array, | ||||
| /// and locations where result and error are saved, respectively. Always | ||||
| /// returns nothing (from the lua point of view). | ||||
| static int nlua_exec_lua_string_api(lua_State *const lstate) | ||||
|     FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   const String *str = (const String *)lua_touserdata(lstate, 1); | ||||
|   const Array *args = (const Array *)lua_touserdata(lstate, 2); | ||||
|   Object *retval = (Object *)lua_touserdata(lstate, 3); | ||||
|   Error *err = (Error *)lua_touserdata(lstate, 4); | ||||
|  | ||||
|   lua_pop(lstate, 4); | ||||
|  | ||||
|   if (luaL_loadbuffer(lstate, str->data, str->size, "<nvim>")) { | ||||
|     size_t len; | ||||
|     const char *str = lua_tolstring(lstate, -1, &len); | ||||
|     api_set_error(err, kErrorTypeValidation, | ||||
|                   "Error loading lua: %.*s", (int)len, str); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   for (size_t i = 0; i < args->size; i++) { | ||||
|     nlua_push_Object(lstate, args->items[i]); | ||||
|   } | ||||
|  | ||||
|   if (lua_pcall(lstate, (int)args->size, 1, 0)) { | ||||
|     size_t len; | ||||
|     const char *str = lua_tolstring(lstate, -1, &len); | ||||
|     api_set_error(err, kErrorTypeException, | ||||
|                   "Error executing lua: %.*s", (int)len, str); | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   *retval = nlua_pop_Object(lstate, err); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /// Print as a Vim message | ||||
| /// | ||||
| /// @param  lstate  Lua interpreter state. | ||||
| @@ -516,6 +556,28 @@ void executor_eval_lua(const String str, typval_T *const arg, | ||||
|                          (void *)&str, arg, ret_tv); | ||||
| } | ||||
|  | ||||
| /// Execute lua string | ||||
| /// | ||||
| /// Used for nvim_execute_lua(). | ||||
| /// | ||||
| /// @param[in]  str  String to execute. | ||||
| /// @param[in]  args array of ... args | ||||
| /// @param[out]  err  Location where error will be saved. | ||||
| /// | ||||
| /// @return Return value of the execution. | ||||
| Object executor_exec_lua_api(const String str, const Array args, Error *err) | ||||
| { | ||||
|   if (global_lstate == NULL) { | ||||
|     global_lstate = init_lua(); | ||||
|   } | ||||
|  | ||||
|   Object retval = NIL; | ||||
|   NLUA_CALL_C_FUNCTION_4(global_lstate, nlua_exec_lua_string_api, 0, | ||||
|                          (void *)&str, (void *)&args, &retval, err); | ||||
|   return retval; | ||||
| } | ||||
|  | ||||
|  | ||||
| /// Run lua string | ||||
| /// | ||||
| /// Used for :lua. | ||||
|   | ||||
| @@ -81,6 +81,36 @@ describe('api', function() | ||||
|     end) | ||||
|   end) | ||||
|  | ||||
|   describe('nvim_execute_lua', function() | ||||
|     it('works', function() | ||||
|       meths.execute_lua('vim.api.nvim_set_var("test", 3)', {}) | ||||
|       eq(3, meths.get_var('test')) | ||||
|  | ||||
|       eq(17, meths.execute_lua('a, b = ...\nreturn a + b', {10,7})) | ||||
|  | ||||
|       eq(NIL, meths.execute_lua('function xx(a,b)\nreturn a..b\nend',{})) | ||||
|       eq("xy", meths.execute_lua('return xx(...)', {'x','y'})) | ||||
|     end) | ||||
|  | ||||
|     it('reports errors', function() | ||||
|       eq({false, 'Error loading lua: [string "<nvim>"]:1: '.. | ||||
|                  "'=' expected near '+'"}, | ||||
|          meth_pcall(meths.execute_lua, 'a+*b', {})) | ||||
|  | ||||
|       eq({false, 'Error loading lua: [string "<nvim>"]:1: '.. | ||||
|                  "unexpected symbol near '1'"}, | ||||
|          meth_pcall(meths.execute_lua, '1+2', {})) | ||||
|  | ||||
|       eq({false, 'Error loading lua: [string "<nvim>"]:1: '.. | ||||
|                  "unexpected symbol"}, | ||||
|          meth_pcall(meths.execute_lua, 'aa=bb\0', {})) | ||||
|  | ||||
|       eq({false, 'Error executing lua: [string "<nvim>"]:1: '.. | ||||
|                  "attempt to call global 'bork' (a nil value)"}, | ||||
|          meth_pcall(meths.execute_lua, 'bork()', {})) | ||||
|     end) | ||||
|   end) | ||||
|  | ||||
|   describe('nvim_input', function() | ||||
|     it("VimL error: does NOT fail, updates v:errmsg", function() | ||||
|       local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Björn Linse
					Björn Linse