diff options
Diffstat (limited to 'src/nvim/viml/executor/executor.c')
| -rw-r--r-- | src/nvim/viml/executor/executor.c | 576 |
1 files changed, 0 insertions, 576 deletions
diff --git a/src/nvim/viml/executor/executor.c b/src/nvim/viml/executor/executor.c deleted file mode 100644 index 826460772e..0000000000 --- a/src/nvim/viml/executor/executor.c +++ /dev/null @@ -1,576 +0,0 @@ -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> - -#include "nvim/misc1.h" -#include "nvim/getchar.h" -#include "nvim/garray.h" -#include "nvim/func_attr.h" -#include "nvim/api/private/defs.h" -#include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" -#include "nvim/vim.h" -#include "nvim/ex_getln.h" -#include "nvim/message.h" -#include "nvim/memline.h" -#include "nvim/buffer_defs.h" -#include "nvim/macros.h" -#include "nvim/screen.h" -#include "nvim/cursor.h" -#include "nvim/undo.h" -#include "nvim/ascii.h" - -#include "nvim/viml/executor/executor.h" -#include "nvim/viml/executor/converter.h" - -typedef struct { - Error err; - String lua_err_str; -} LuaError; - -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "viml/executor/vim_module.generated.h" -# include "viml/executor/executor.c.generated.h" -#endif - -/// Name of the run code for use in messages -#define NLUA_EVAL_NAME "<VimL compiled string>" - -/// Call C function which does not expect any arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -#define NLUA_CALL_C_FUNCTION_0(lstate, function, numret) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_call(lstate, 0, numret); \ - } while (0) -/// Call C function which expects one argument -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_1(lstate, function, numret, a1) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_call(lstate, 1, numret); \ - } while (0) -/// Call C function which expects two arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_2(lstate, function, numret, a1, a2) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_call(lstate, 2, numret); \ - } while (0) -/// Call C function which expects three arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_3(lstate, function, numret, a1, a2, a3) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_pushlightuserdata(lstate, a3); \ - lua_call(lstate, 3, numret); \ - } while (0) -/// Call C function which expects five arguments -/// -/// @param function Called function -/// @param numret Number of returned arguments -/// @param a… Supplied argument (should be a void* pointer) -#define NLUA_CALL_C_FUNCTION_4(lstate, function, numret, a1, a2, a3, a4) \ - do { \ - lua_pushcfunction(lstate, &function); \ - lua_pushlightuserdata(lstate, a1); \ - lua_pushlightuserdata(lstate, a2); \ - lua_pushlightuserdata(lstate, a3); \ - lua_pushlightuserdata(lstate, a4); \ - lua_call(lstate, 4, numret); \ - } while (0) - -/// Convert lua error into a Vim error message -/// -/// @param lstate Lua interpreter state. -/// @param[in] msg Message base, must contain one `%s`. -static void nlua_error(lua_State *const lstate, const char *const msg) - FUNC_ATTR_NONNULL_ALL -{ - size_t len; - const char *const str = lua_tolstring(lstate, -1, &len); - - emsgf(msg, (int)len, str); - - lua_pop(lstate, 1); -} - -/// Compare two strings, ignoring case -/// -/// Expects two values on the stack: compared strings. Returns one of the -/// following numbers: 0, -1 or 1. -/// -/// Does no error handling: never call it with non-string or with some arguments -/// omitted. -static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const char *s1 = luaL_checklstring(lstate, 1, NULL); - const char *s2 = luaL_checklstring(lstate, 2, NULL); - const int ret = STRICMP(s1, s2); - lua_pop(lstate, 2); - lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0))); - return 1; -} - -/// Evaluate lua string -/// -/// Expects two values on the stack: string to evaluate, pointer to the -/// location where result is saved. Always returns nothing (from the lua point -/// of view). -static int nlua_exec_lua_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 2); - lua_pop(lstate, 2); - - if (luaL_loadbuffer(lstate, str->data, str->size, NLUA_EVAL_NAME)) { - nlua_error(lstate, _("E5104: Error while creating lua chunk: %.*s")); - return 0; - } - if (lua_pcall(lstate, 0, 1, 0)) { - nlua_error(lstate, _("E5105: Error while calling lua chunk: %.*s")); - return 0; - } - if (!nlua_pop_typval(lstate, ret_tv)) { - return 0; - } - return 0; -} - -/// Evaluate lua string for each line in range -/// -/// Expects two values on the stack: string to evaluate and pointer to integer -/// array with line range. Always returns nothing (from the lua point of view). -static int nlua_exec_luado_string(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - const linenr_T *const range = (const linenr_T *)lua_touserdata(lstate, 2); - lua_pop(lstate, 2); - -#define DOSTART "return function(line, linenr) " -#define DOEND " end" - const size_t lcmd_len = (str->size - + (sizeof(DOSTART) - 1) - + (sizeof(DOEND) - 1)); - char *lcmd; - if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; - } else { - lcmd = xmalloc(lcmd_len + 1); - } - memcpy(lcmd, DOSTART, sizeof(DOSTART) - 1); - memcpy(lcmd + sizeof(DOSTART) - 1, str->data, str->size); - memcpy(lcmd + sizeof(DOSTART) - 1 + str->size, DOEND, sizeof(DOEND) - 1); -#undef DOSTART -#undef DOEND - - if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { - nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s")); - if (lcmd_len >= IOSIZE) { - xfree(lcmd); - } - return 0; - } - if (lcmd_len >= IOSIZE) { - xfree(lcmd); - } - if (lua_pcall(lstate, 0, 1, 0)) { - nlua_error(lstate, _("E5110: Error while creating lua function: %.*s")); - return 0; - } - for (linenr_T l = range[0]; l <= range[1]; l++) { - if (l > curbuf->b_ml.ml_line_count) { - break; - } - lua_pushvalue(lstate, -1); - lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false)); - lua_pushnumber(lstate, (lua_Number)l); - if (lua_pcall(lstate, 2, 1, 0)) { - nlua_error(lstate, _("E5111: Error while calling lua function: %.*s")); - break; - } - if (lua_isstring(lstate, -1)) { - size_t new_line_len; - const char *const new_line = lua_tolstring(lstate, -1, &new_line_len); - char *const new_line_transformed = xmemdupz(new_line, new_line_len); - for (size_t i = 0; i < new_line_len; i++) { - if (new_line_transformed[i] == NUL) { - new_line_transformed[i] = '\n'; - } - } - ml_replace(l, (char_u *)new_line_transformed, false); - changed_bytes(l, 0); - } - lua_pop(lstate, 1); - } - lua_pop(lstate, 1); - check_cursor(); - update_screen(NOT_VALID); - return 0; -} - -/// Evaluate lua file -/// -/// Expects one value on the stack: file to evaluate. Always returns nothing -/// (from the lua point of view). -static int nlua_exec_lua_file(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - const char *const filename = (const char *)lua_touserdata(lstate, 1); - lua_pop(lstate, 1); - - if (luaL_loadfile(lstate, filename)) { - nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); - return 0; - } - if (lua_pcall(lstate, 0, 0, 0)) { - nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); - return 0; - } - return 0; -} - -/// Initialize lua interpreter state -/// -/// Called by lua interpreter itself to initialize state. -static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL -{ - // stricmp - lua_pushcfunction(lstate, &nlua_stricmp); - lua_setglobal(lstate, "stricmp"); - - // print - lua_pushcfunction(lstate, &nlua_print); - lua_setglobal(lstate, "print"); - - // debug.debug - lua_getglobal(lstate, "debug"); - lua_pushcfunction(lstate, &nlua_debug); - lua_setfield(lstate, -2, "debug"); - lua_pop(lstate, 1); - - // vim - if (luaL_dostring(lstate, (char *)&vim_module[0])) { - nlua_error(lstate, _("E5106: Error while creating vim module: %.*s")); - return 1; - } - // vim.api - nlua_add_api_functions(lstate); - // vim.types, vim.type_idx, vim.val_idx - nlua_init_types(lstate); - lua_setglobal(lstate, "vim"); - return 0; -} - -/// Initialize lua interpreter -/// -/// Crashes NeoVim if initialization fails. Should be called once per lua -/// interpreter instance. -static lua_State *init_lua(void) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT -{ - lua_State *lstate = luaL_newstate(); - if (lstate == NULL) { - EMSG(_("E970: Failed to initialize lua interpreter")); - preserve_exit(); - } - luaL_openlibs(lstate); - NLUA_CALL_C_FUNCTION_0(lstate, nlua_state_init, 0); - return lstate; -} - -static lua_State *global_lstate = NULL; - -/// Execute lua string -/// -/// @param[in] str String to execute. -/// @param[out] ret_tv Location where result will be saved. -/// -/// @return Result of the execution. -void executor_exec_lua(const String str, typval_T *const ret_tv) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - - NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_lua_string, 0, - (void *)&str, ret_tv); -} - -/// Evaluate lua string -/// -/// Used for luaeval(). Expects three values on the stack: -/// -/// 1. String to evaluate. -/// 2. _A value. -/// 3. Pointer to location where result is saved. -/// -/// @param[in,out] lstate Lua interpreter state. -static int nlua_eval_lua_string(lua_State *const lstate) - FUNC_ATTR_NONNULL_ALL -{ - const String *const str = (const String *)lua_touserdata(lstate, 1); - typval_T *const arg = (typval_T *)lua_touserdata(lstate, 2); - typval_T *const ret_tv = (typval_T *)lua_touserdata(lstate, 3); - lua_pop(lstate, 3); - - garray_T str_ga; - ga_init(&str_ga, 1, 80); -#define EVALHEADER "local _A=select(1,...) return (" - const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str->size + 1; - char *lcmd; - if (lcmd_len < IOSIZE) { - lcmd = (char *)IObuff; - } else { - lcmd = xmalloc(lcmd_len); - } - memcpy(lcmd, EVALHEADER, sizeof(EVALHEADER) - 1); - memcpy(lcmd + sizeof(EVALHEADER) - 1, str->data, str->size); - lcmd[lcmd_len - 1] = ')'; -#undef EVALHEADER - if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) { - nlua_error(lstate, - _("E5107: Error while creating lua chunk for luaeval(): %.*s")); - if (lcmd != (char *)IObuff) { - xfree(lcmd); - } - return 0; - } - if (lcmd != (char *)IObuff) { - xfree(lcmd); - } - - if (arg == NULL || arg->v_type == VAR_UNKNOWN) { - lua_pushnil(lstate); - } else { - nlua_push_typval(lstate, arg); - } - if (lua_pcall(lstate, 1, 1, 0)) { - nlua_error(lstate, - _("E5108: Error while calling lua chunk for luaeval(): %.*s")); - return 0; - } - if (!nlua_pop_typval(lstate, ret_tv)) { - return 0; - } - - return 0; -} - -/// Print as a Vim message -/// -/// @param lstate Lua interpreter state. -static int nlua_print(lua_State *const lstate) - FUNC_ATTR_NONNULL_ALL -{ -#define PRINT_ERROR(msg) \ - do { \ - errmsg = msg; \ - errmsg_len = sizeof(msg) - 1; \ - goto nlua_print_error; \ - } while (0) - const int nargs = lua_gettop(lstate); - lua_getglobal(lstate, "tostring"); - const char *errmsg = NULL; - size_t errmsg_len = 0; - garray_T msg_ga; - ga_init(&msg_ga, 1, 80); - int curargidx = 1; - for (; curargidx <= nargs; curargidx++) { - lua_pushvalue(lstate, -1); // tostring - lua_pushvalue(lstate, curargidx); // arg - if (lua_pcall(lstate, 1, 1, 0)) { - errmsg = lua_tolstring(lstate, -1, &errmsg_len); - goto nlua_print_error; - } - size_t len; - const char *const s = lua_tolstring(lstate, -1, &len); - if (s == NULL) { - PRINT_ERROR( - "<Unknown error: lua_tolstring returned NULL for tostring result>"); - } - ga_concat_len(&msg_ga, s, len); - if (curargidx < nargs) { - ga_append(&msg_ga, ' '); - } - lua_pop(lstate, 1); - } -#undef PRINT_ERROR - lua_pop(lstate, nargs + 1); - ga_append(&msg_ga, NUL); - { - const size_t len = (size_t)msg_ga.ga_len - 1; - char *const str = (char *)msg_ga.ga_data; - - for (size_t i = 0; i < len;) { - const size_t start = i; - while (i < len) { - switch (str[i]) { - case NUL: { - str[i] = NL; - i++; - continue; - } - case NL: { - str[i] = NUL; - i++; - break; - } - default: { - i++; - continue; - } - } - break; - } - msg((char_u *)str + start); - } - if (str[len - 1] == NUL) { // Last was newline - msg((char_u *)""); - } - } - ga_clear(&msg_ga); - return 0; -nlua_print_error: - emsgf(_("E5114: Error while converting print argument #%i: %.*s"), - curargidx, errmsg_len, errmsg); - ga_clear(&msg_ga); - lua_pop(lstate, lua_gettop(lstate)); - return 0; -} - -/// debug.debug implementation: interaction with user while debugging -/// -/// @param lstate Lua interpreter state. -int nlua_debug(lua_State *lstate) - FUNC_ATTR_NONNULL_ALL -{ - const typval_T input_args[] = { - { - .v_lock = VAR_FIXED, - .v_type = VAR_STRING, - .vval.v_string = (char_u *)"lua_debug> ", - }, - { - .v_type = VAR_UNKNOWN, - }, - }; - for (;;) { - lua_settop(lstate, 0); - typval_T input; - get_user_input(input_args, &input, false); - msg_putchar('\n'); // Avoid outputting on input line. - if (input.v_type != VAR_STRING - || input.vval.v_string == NULL - || *input.vval.v_string == NUL - || STRCMP(input.vval.v_string, "cont") == 0) { - tv_clear(&input); - return 0; - } - if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string, - STRLEN(input.vval.v_string), "=(debug command)")) { - nlua_error(lstate, _("E5115: Error while loading debug string: %.*s")); - } - tv_clear(&input); - if (lua_pcall(lstate, 0, 0, 0)) { - nlua_error(lstate, _("E5116: Error while calling debug string: %.*s")); - } - } - return 0; -} - -/// Evaluate lua string -/// -/// Used for luaeval(). -/// -/// @param[in] str String to execute. -/// @param[in] arg Second argument to `luaeval()`. -/// @param[out] ret_tv Location where result will be saved. -/// -/// @return Result of the execution. -void executor_eval_lua(const String str, typval_T *const arg, - typval_T *const ret_tv) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - - NLUA_CALL_C_FUNCTION_3(global_lstate, nlua_eval_lua_string, 0, - (void *)&str, arg, ret_tv); -} - -/// Run lua string -/// -/// Used for :lua. -/// -/// @param eap VimL command being run. -void ex_lua(exarg_T *const eap) - FUNC_ATTR_NONNULL_ALL -{ - size_t len; - char *const code = script_get(eap, &len); - if (eap->skip) { - xfree(code); - return; - } - typval_T tv = { .v_type = VAR_UNKNOWN }; - executor_exec_lua((String) { .data = code, .size = len }, &tv); - tv_clear(&tv); - xfree(code); -} - -/// Run lua string for each line in range -/// -/// Used for :luado. -/// -/// @param eap VimL command being run. -void ex_luado(exarg_T *const eap) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - if (u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) { - EMSG(_("cannot save undo information")); - return; - } - const String cmd = { - .size = STRLEN(eap->arg), - .data = (char *)eap->arg, - }; - const linenr_T range[] = { eap->line1, eap->line2 }; - NLUA_CALL_C_FUNCTION_2(global_lstate, nlua_exec_luado_string, 0, - (void *)&cmd, (void *)range); -} - -/// Run lua file -/// -/// Used for :luafile. -/// -/// @param eap VimL command being run. -void ex_luafile(exarg_T *const eap) - FUNC_ATTR_NONNULL_ALL -{ - if (global_lstate == NULL) { - global_lstate = init_lua(); - } - NLUA_CALL_C_FUNCTION_1(global_lstate, nlua_exec_lua_file, 0, - (void *)eap->arg); -} |