mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 01:34:25 +00:00 
			
		
		
		
	api: execute lua directly from the remote api
This commit is contained in:
		@@ -15,6 +15,7 @@
 | 
				
			|||||||
#include "nvim/api/private/defs.h"
 | 
					#include "nvim/api/private/defs.h"
 | 
				
			||||||
#include "nvim/api/buffer.h"
 | 
					#include "nvim/api/buffer.h"
 | 
				
			||||||
#include "nvim/msgpack_rpc/channel.h"
 | 
					#include "nvim/msgpack_rpc/channel.h"
 | 
				
			||||||
 | 
					#include "nvim/lua/executor.h"
 | 
				
			||||||
#include "nvim/vim.h"
 | 
					#include "nvim/vim.h"
 | 
				
			||||||
#include "nvim/buffer.h"
 | 
					#include "nvim/buffer.h"
 | 
				
			||||||
#include "nvim/file_search.h"
 | 
					#include "nvim/file_search.h"
 | 
				
			||||||
@@ -254,6 +255,25 @@ free_vim_args:
 | 
				
			|||||||
  return rv;
 | 
					  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`.
 | 
					/// Calculates the number of display cells occupied by `text`.
 | 
				
			||||||
/// <Tab> counts as one cell.
 | 
					/// <Tab> counts as one cell.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -373,6 +373,46 @@ static int nlua_eval_lua_string(lua_State *const lstate)
 | 
				
			|||||||
  return 0;
 | 
					  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
 | 
					/// Print as a Vim message
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// @param  lstate  Lua interpreter state.
 | 
					/// @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);
 | 
					                         (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
 | 
					/// Run lua string
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Used for :lua.
 | 
					/// Used for :lua.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,6 +81,36 @@ describe('api', function()
 | 
				
			|||||||
    end)
 | 
					    end)
 | 
				
			||||||
  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()
 | 
					  describe('nvim_input', function()
 | 
				
			||||||
    it("VimL error: does NOT fail, updates v:errmsg", function()
 | 
					    it("VimL error: does NOT fail, updates v:errmsg", function()
 | 
				
			||||||
      local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>")
 | 
					      local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>")
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user