aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/executor.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-01-25 18:31:31 +0000
commit9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch)
tree607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /src/nvim/lua/executor.c
parent9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff)
parent3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff)
downloadrneovim-9243becbedbb6a1592208051f8fa2b090dcc5e7d.tar.gz
rneovim-9243becbedbb6a1592208051f8fa2b090dcc5e7d.tar.bz2
rneovim-9243becbedbb6a1592208051f8fa2b090dcc5e7d.zip
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'src/nvim/lua/executor.c')
-rw-r--r--src/nvim/lua/executor.c409
1 files changed, 312 insertions, 97 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index d1d1480696..5ffd90fddd 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1,17 +1,22 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+#include <assert.h>
+#include <inttypes.h>
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
+#include <stddef.h>
+#include <string.h>
#include <tree_sitter/api.h>
+#include <uv.h>
+#include "klib/kvec.h"
#include "luv/luv.h"
+#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/api/vim.h"
#include "nvim/ascii.h"
-#include "nvim/assert.h"
#include "nvim/buffer_defs.h"
#include "nvim/change.h"
#include "nvim/cursor.h"
@@ -19,27 +24,39 @@
#include "nvim/eval.h"
#include "nvim/eval/funcs.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
#include "nvim/event/time.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_getln.h"
-#include "nvim/extmark.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/keycodes.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/lua/stdlib.h"
#include "nvim/lua/treesitter.h"
#include "nvim/macros.h"
-#include "nvim/map.h"
+#include "nvim/main.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/option_defs.h"
+#include "nvim/os/fileio.h"
#include "nvim/os/os.h"
+#include "nvim/path.h"
+#include "nvim/pos.h"
#include "nvim/profile.h"
#include "nvim/runtime.h"
+#include "nvim/strings.h"
+#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/usercmd.h"
#include "nvim/version.h"
@@ -188,8 +205,8 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags
if (status) {
if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) {
// consider out of memory errors unrecoverable, just like xmalloc()
- mch_errmsg(e_outofmem);
- mch_errmsg("\n");
+ os_errmsg(e_outofmem);
+ os_errmsg("\n");
preserve_exit();
}
const char *error = lua_tostring(lstate, -1);
@@ -241,10 +258,10 @@ static int nlua_luv_thread_common_cfpcall(lua_State *lstate, int nargs, int nres
if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) {
// Terminate this thread, as the main thread may be able to continue
// execution.
- mch_errmsg(e_outofmem);
- mch_errmsg("\n");
+ os_errmsg(e_outofmem);
+ os_errmsg("\n");
lua_close(lstate);
-#ifdef WIN32
+#ifdef MSWIN
ExitThread(0);
#else
pthread_exit(0);
@@ -306,6 +323,36 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate)
return 1;
}
+/// Copies args starting at `lua_arg0` to Lua `_G.arg`, and sets `_G.arg[0]` to the scriptname.
+///
+/// Example (arg[0] => "foo.lua", arg[1] => "--arg1", …):
+/// nvim -l foo.lua --arg1 --arg2
+///
+/// @note Lua CLI sets args before "-e" as _negative_ `_G.arg` indices, but we currently don't.
+///
+/// @see https://www.lua.org/pil/1.4.html
+/// @see https://github.com/premake/premake-core/blob/1c1304637f4f5e50ba8c57aae8d1d80ec3b7aaf2/src/host/premake.c#L563-L594
+///
+/// @returns number of args
+static int nlua_init_argv(lua_State *const L, char **argv, int argc, int lua_arg0)
+{
+ int i = 0;
+ lua_newtable(L); // _G.arg
+
+ if (lua_arg0 > 0) {
+ lua_pushstring(L, argv[lua_arg0 - 1]);
+ lua_rawseti(L, -2, 0); // _G.arg[0] = "foo.lua"
+
+ for (; lua_arg0 >= 0 && i + lua_arg0 < argc; i++) {
+ lua_pushstring(L, argv[i + lua_arg0]);
+ lua_rawseti(L, -2, i + 1); // _G.arg[i+1] = "--foo"
+ }
+ }
+
+ lua_setglobal(L, "arg");
+ return i;
+}
+
static void nlua_schedule_event(void **argv)
{
LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
@@ -396,7 +443,7 @@ static int nlua_wait(lua_State *lstate)
bool fast_only = false;
if (lua_top >= 4) {
- fast_only = lua_toboolean(lstate, 4);
+ fast_only = lua_toboolean(lstate, 4);
}
MultiQueue *loop_events = fast_only || in_fast_callback > 0
@@ -581,14 +628,79 @@ static bool nlua_init_packages(lua_State *lstate)
lua_getglobal(lstate, "require");
lua_pushstring(lstate, "vim._init_packages");
if (nlua_pcall(lstate, 1, 0)) {
- mch_errmsg(lua_tostring(lstate, -1));
- mch_errmsg("\n");
+ os_errmsg((char *)lua_tostring(lstate, -1));
+ os_errmsg("\n");
return false;
}
return true;
}
+/// "vim.ui_attach(ns_id, {ext_foo=true}, cb)" function
+static int nlua_ui_attach(lua_State *lstate)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1);
+
+ if (!ns_initialized(ns_id)) {
+ return luaL_error(lstate, "invalid ns_id");
+ }
+ if (!lua_istable(lstate, 2)) {
+ return luaL_error(lstate, "ext_widgets must be a table");
+ }
+ if (!lua_isfunction(lstate, 3)) {
+ return luaL_error(lstate, "callback must be a Lua function");
+ }
+
+ bool ext_widgets[kUIGlobalCount] = { false };
+ bool tbl_has_true_val = false;
+
+ lua_pushvalue(lstate, 2);
+ lua_pushnil(lstate);
+ while (lua_next(lstate, -2)) {
+ // [dict, key, val]
+ size_t len;
+ const char *s = lua_tolstring(lstate, -2, &len);
+ bool val = lua_toboolean(lstate, -1);
+
+ for (size_t i = 0; i < kUIGlobalCount; i++) {
+ if (strequal(s, ui_ext_names[i])) {
+ if (val) {
+ tbl_has_true_val = true;
+ }
+ ext_widgets[i] = val;
+ goto ok;
+ }
+ }
+
+ return luaL_error(lstate, "Unexpected key: %s", s);
+ok:
+ lua_pop(lstate, 1);
+ }
+
+ if (!tbl_has_true_val) {
+ return luaL_error(lstate, "ext_widgets table must contain at least one 'true' value");
+ }
+
+ LuaRef ui_event_cb = nlua_ref_global(lstate, 3);
+ ui_add_cb(ns_id, ui_event_cb, ext_widgets);
+ return 0;
+}
+
+/// "vim.ui_detach(ns_id)" function
+static int nlua_ui_detach(lua_State *lstate)
+ FUNC_ATTR_NONNULL_ALL
+{
+ uint32_t ns_id = (uint32_t)luaL_checkinteger(lstate, 1);
+
+ if (!ns_initialized(ns_id)) {
+ return luaL_error(lstate, "invalid ns_id");
+ }
+
+ ui_remove_cb(ns_id);
+ return 0;
+}
+
/// Initialize lua interpreter state
///
/// Called by lua interpreter itself to initialize state.
@@ -604,7 +716,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "debug");
lua_pop(lstate, 1);
-#ifdef WIN32
+#ifdef MSWIN
// os.getenv
lua_getglobal(lstate, "os");
lua_pushcfunction(lstate, &nlua_getenv);
@@ -649,6 +761,14 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_wait);
lua_setfield(lstate, -2, "wait");
+ // ui_attach
+ lua_pushcfunction(lstate, &nlua_ui_attach);
+ lua_setfield(lstate, -2, "ui_attach");
+
+ // ui_detach
+ lua_pushcfunction(lstate, &nlua_ui_detach);
+ lua_setfield(lstate, -2, "ui_detach");
+
nlua_common_vim_init(lstate, false);
// patch require() (only for --startuptime)
@@ -675,10 +795,8 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return true;
}
-/// Initialize global lua interpreter
-///
-/// Crashes Nvim if initialization fails.
-void nlua_init(void)
+/// Initializes global Lua interpreter, or exits Nvim on failure.
+void nlua_init(char **argv, int argc, int lua_arg0)
{
#ifdef NLUA_TRACK_REFS
const char *env = os_getenv("NVIM_LUA_NOTRACK");
@@ -689,20 +807,19 @@ void nlua_init(void)
lua_State *lstate = luaL_newstate();
if (lstate == NULL) {
- mch_errmsg(_("E970: Failed to initialize lua interpreter\n"));
+ os_errmsg(_("E970: Failed to initialize lua interpreter\n"));
os_exit(1);
}
luaL_openlibs(lstate);
if (!nlua_state_init(lstate)) {
- mch_errmsg(_("E970: Failed to initialize builtin lua modules\n"));
+ os_errmsg(_("E970: Failed to initialize builtin lua modules\n"));
os_exit(1);
}
luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem);
-
global_lstate = lstate;
-
main_thread = uv_thread_self();
+ nlua_init_argv(lstate, argv, argc, lua_arg0);
}
static lua_State *nlua_thread_acquire_vm(void)
@@ -935,8 +1052,8 @@ static int nlua_require(lua_State *const lstate)
time_push(&rel_time, &start_time);
int status = lua_pcall(lstate, 1, 1, 0);
if (status == 0) {
- vim_snprintf((char *)IObuff, IOSIZE, "require('%s')", name);
- time_msg((char *)IObuff, &start_time);
+ vim_snprintf(IObuff, IOSIZE, "require('%s')", name);
+ time_msg(IObuff, &start_time);
}
time_pop(rel_time);
@@ -967,12 +1084,12 @@ static int nlua_debug(lua_State *lstate)
if (input.v_type != VAR_STRING
|| input.vval.v_string == NULL
|| *input.vval.v_string == NUL
- || STRCMP(input.vval.v_string, "cont") == 0) {
+ || 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)")) {
+ strlen(input.vval.v_string), "=(debug command)")) {
nlua_error(lstate, _("E5115: Error while loading debug string: %.*s"));
} else if (nlua_pcall(lstate, 0, 0)) {
nlua_error(lstate, _("E5116: Error while calling debug string: %.*s"));
@@ -990,7 +1107,7 @@ int nlua_in_fast_event(lua_State *lstate)
static bool viml_func_is_fast(const char *name)
{
- const EvalFuncDef *const fdef = find_internal_func((const char *)name);
+ const EvalFuncDef *const fdef = find_internal_func(name);
if (fdef) {
return fdef->fast;
}
@@ -1027,15 +1144,15 @@ int nlua_call(lua_State *lstate)
// TODO(bfredl): this should be simplified in error handling refactor
force_abort = false;
suppress_errthrow = false;
- current_exception = NULL;
+ did_throw = false;
did_emsg = false;
try_start();
typval_T rettv;
funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.firstline = curwin->w_cursor.lnum;
- funcexe.lastline = curwin->w_cursor.lnum;
- funcexe.evaluate = true;
+ funcexe.fe_firstline = curwin->w_cursor.lnum;
+ funcexe.fe_lastline = curwin->w_cursor.lnum;
+ funcexe.fe_evaluate = true;
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (TRY_WRAP) to capture abort-causing non-exception errors.
(void)call_func((char *)name, (int)name_len, &rettv, nargs, vim_args, &funcexe);
@@ -1093,13 +1210,14 @@ static int nlua_rpc(lua_State *lstate, bool request)
Object result = rpc_send_call(chan_id, name, args, &res_mem, &err);
if (!ERROR_SET(&err)) {
nlua_push_Object(lstate, result, false);
- arena_mem_free(res_mem, NULL);
+ arena_mem_free(res_mem);
}
} else {
if (!rpc_send_event(chan_id, name, args)) {
api_set_error(&err, kErrorTypeValidation,
"Invalid channel: %" PRIu64, chan_id);
}
+ api_free_array(args); // TODO(bfredl): no
}
check_err:
@@ -1124,7 +1242,7 @@ static int nlua_empty_dict_tostring(lua_State *lstate)
return 1;
}
-#ifdef WIN32
+#ifdef MSWIN
/// os.getenv: override os.getenv to maintain coherency. #9681
///
/// uv_os_setenv uses SetEnvironmentVariableW which does not update _environ.
@@ -1224,7 +1342,7 @@ void nlua_typval_eval(const String str, typval_T *const arg, typval_T *const ret
const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str.size + 1;
char *lcmd;
if (lcmd_len < IOSIZE) {
- lcmd = (char *)IObuff;
+ lcmd = IObuff;
} else {
lcmd = xmalloc(lcmd_len);
}
@@ -1234,7 +1352,7 @@ void nlua_typval_eval(const String str, typval_T *const arg, typval_T *const ret
#undef EVALHEADER
nlua_typval_exec(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv);
- if (lcmd != (char *)IObuff) {
+ if (lcmd != IObuff) {
xfree(lcmd);
}
}
@@ -1248,7 +1366,7 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg
const size_t lcmd_len = sizeof(CALLHEADER) - 1 + len + sizeof(CALLSUFFIX) - 1;
char *lcmd;
if (lcmd_len < IOSIZE) {
- lcmd = (char *)IObuff;
+ lcmd = IObuff;
} else {
lcmd = xmalloc(lcmd_len);
}
@@ -1261,7 +1379,7 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg
nlua_typval_exec(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv);
- if (lcmd != (char *)IObuff) {
+ if (lcmd != IObuff) {
xfree(lcmd);
}
}
@@ -1322,11 +1440,11 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
estack_push(ETYPE_SCRIPT, name, 0);
garray_T ga;
- char_u *line = NULL;
+ char *line = NULL;
- ga_init(&ga, (int)sizeof(char_u *), 10);
- while ((line = (char_u *)fgetline(0, cookie, 0, false)) != NULL) {
- GA_APPEND(char_u *, &ga, line);
+ ga_init(&ga, (int)sizeof(char *), 10);
+ while ((line = fgetline(0, cookie, 0, false)) != NULL) {
+ GA_APPEND(char *, &ga, line);
}
char *code = ga_concat_strings_sep(&ga, "\n");
size_t len = strlen(code);
@@ -1348,23 +1466,22 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
/// @param[in] argcount Count of typval arguments
/// @param[in] argvars Typval Arguments
/// @param[out] rettv The return value from the called function.
-int typval_exec_lua_callable(lua_State *lstate, LuaCallable lua_cb, int argcount, typval_T *argvars,
- typval_T *rettv)
+int typval_exec_lua_callable(LuaRef lua_cb, int argcount, typval_T *argvars, typval_T *rettv)
{
- LuaRef cb = lua_cb.func_ref;
+ lua_State *lstate = global_lstate;
- nlua_pushref(lstate, cb);
+ nlua_pushref(lstate, lua_cb);
PUSH_ALL_TYPVALS(lstate, argvars, argcount, false);
if (nlua_pcall(lstate, argcount, 1)) {
nlua_print(lstate);
- return ERROR_OTHER;
+ return FCERR_OTHER;
}
nlua_pop_typval(lstate, rettv);
- return ERROR_NONE;
+ return FCERR_NONE;
}
/// Execute Lua string
@@ -1422,9 +1539,10 @@ bool nlua_ref_is_function(LuaRef ref)
/// @param name if non-NULL, sent to callback as first arg
/// if NULL, only args are used
/// @param retval if true, convert return value to Object
-/// if false, discard return value
+/// if false, only check if return value is truthy
/// @param err Error details, if any (if NULL, errors are echoed)
-/// @return Return value of function, if retval was set. Otherwise NIL.
+/// @return Return value of function, if retval was set. Otherwise
+/// BOOLEAN_OBJ(true) or NIL.
Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err)
{
lua_State *const lstate = global_lstate;
@@ -1438,7 +1556,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro
nlua_push_Object(lstate, args.items[i], false);
}
- if (nlua_pcall(lstate, nargs, retval ? 1 : 0)) {
+ if (nlua_pcall(lstate, nargs, 1)) {
// if err is passed, the caller will deal with the error.
if (err) {
size_t len;
@@ -1458,7 +1576,10 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Erro
}
return nlua_pop_Object(lstate, false, err);
} else {
- return NIL;
+ bool value = lua_toboolean(lstate, -1);
+ lua_pop(lstate, 1);
+
+ return value ? BOOLEAN_OBJ(true) : NIL;
}
}
@@ -1524,7 +1645,7 @@ void ex_luado(exarg_T *const eap)
+ (sizeof(DOEND) - 1));
char *lcmd;
if (lcmd_len < IOSIZE) {
- lcmd = (char *)IObuff;
+ lcmd = IObuff;
} else {
lcmd = xmalloc(lcmd_len + 1);
}
@@ -1561,7 +1682,7 @@ void ex_luado(exarg_T *const eap)
break;
}
if (lua_isstring(lstate, -1)) {
- size_t old_line_len = STRLEN(old_line);
+ size_t old_line_len = strlen(old_line);
size_t new_line_len;
const char *const new_line = lua_tolstring(lstate, -1, &new_line_len);
@@ -1578,7 +1699,7 @@ void ex_luado(exarg_T *const eap)
}
lua_pop(lstate, 1);
check_cursor();
- update_screen(NOT_VALID);
+ redraw_curbuf_later(UPD_NOT_VALID);
}
/// Run lua file
@@ -1592,21 +1713,51 @@ void ex_luafile(exarg_T *const eap)
nlua_exec_file((const char *)eap->arg);
}
-/// execute lua code from a file.
+/// Executes Lua code from a file or "-" (stdin).
///
-/// Note: we call the lua global loadfile as opposed to calling luaL_loadfile
-/// in case loadfile has been overridden in the users environment.
+/// Calls the Lua `loadfile` global as opposed to `luaL_loadfile` in case `loadfile` was overridden
+/// in the user environment.
///
-/// @param path path of the file
+/// @param path Path to the file, may be "-" (stdin) during startup.
///
-/// @return true if everything ok, false if there was an error (echoed)
+/// @return true on success, false on error (echoed) or user canceled (CTRL-c) while reading "-"
+/// (stdin).
bool nlua_exec_file(const char *path)
FUNC_ATTR_NONNULL_ALL
{
lua_State *const lstate = global_lstate;
+ if (!strequal(path, "-")) {
+ lua_getglobal(lstate, "loadfile");
+ lua_pushstring(lstate, path);
+ } else {
+ FileDescriptor *stdin_dup = file_open_stdin();
+
+ StringBuilder sb = KV_INITIAL_VALUE;
+ kv_resize(sb, 64);
+ ptrdiff_t read_size = -1;
+ // Read all input from stdin, unless interrupted (ctrl-c).
+ while (true) {
+ if (got_int) { // User canceled.
+ return false;
+ }
+ read_size = file_read(stdin_dup, IObuff, 64);
+ if (read_size < 0) { // Error.
+ return false;
+ }
+ if (read_size > 0) {
+ kv_concat_len(sb, IObuff, (size_t)read_size);
+ }
+ if (read_size < 64) { // EOF.
+ break;
+ }
+ }
+ kv_push(sb, NUL);
+ file_free(stdin_dup, false);
- lua_getglobal(lstate, "loadfile");
- lua_pushstring(lstate, path);
+ lua_getglobal(lstate, "loadstring");
+ lua_pushstring(lstate, sb.items);
+ kv_destroy(sb);
+ }
if (nlua_pcall(lstate, 1, 2)) {
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
@@ -1662,6 +1813,9 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, tslua_has_language);
lua_setfield(lstate, -2, "_ts_has_language");
+ lua_pushcfunction(lstate, tslua_remove_lang);
+ lua_setfield(lstate, -2, "_ts_remove_language");
+
lua_pushcfunction(lstate, tslua_inspect_lang);
lua_setfield(lstate, -2, "_ts_inspect_language");
@@ -1675,7 +1829,7 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "_ts_get_minimum_language_version");
}
-int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results)
+int nlua_expand_pat(expand_T *xp, char *pat, int *num_results, char ***results)
{
lua_State *const lstate = global_lstate;
int ret = OK;
@@ -1688,7 +1842,7 @@ int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results
luaL_checktype(lstate, -1, LUA_TFUNCTION);
// [ vim, vim._expand_pat, buf ]
- lua_pushlstring(lstate, (const char *)pat, STRLEN(pat));
+ lua_pushlstring(lstate, (const char *)pat, strlen(pat));
if (nlua_pcall(lstate, 1, 2) != 0) {
nlua_error(lstate,
@@ -1723,7 +1877,7 @@ int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char ***results
goto cleanup_array;
}
- GA_APPEND(char_u *, &result_array, (char_u *)string_to_cstr(v.data.string));
+ GA_APPEND(char *, &result_array, string_to_cstr(v.data.string));
}
xp->xp_pattern += prefix_len;
@@ -1749,27 +1903,7 @@ static int nlua_is_thread(lua_State *lstate)
return 1;
}
-// Required functions for lua c functions as VimL callbacks
-
-int nlua_CFunction_func_call(int argcount, typval_T *argvars, typval_T *rettv, void *state)
-{
- lua_State *const lstate = global_lstate;
- LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
-
- return typval_exec_lua_callable(lstate, funcstate->lua_callable,
- argcount, argvars, rettv);
-}
-
-void nlua_CFunction_func_free(void *state)
-{
- lua_State *const lstate = global_lstate;
- LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
-
- nlua_unref_global(lstate, funcstate->lua_callable.func_ref);
- xfree(funcstate);
-}
-
-bool nlua_is_table_from_lua(typval_T *const arg)
+bool nlua_is_table_from_lua(const typval_T *const arg)
{
if (arg->v_type == VAR_DICT) {
return arg->vval.v_dict->lua_table_ref != LUA_NOREF;
@@ -1780,7 +1914,7 @@ bool nlua_is_table_from_lua(typval_T *const arg)
}
}
-char_u *nlua_register_table_as_callable(typval_T *const arg)
+char *nlua_register_table_as_callable(const typval_T *const arg)
{
LuaRef table_ref = LUA_NOREF;
if (arg->v_type == VAR_DICT) {
@@ -1814,11 +1948,9 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
}
lua_pop(lstate, 2); // [table]
- LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));
- state->lua_callable.func_ref = nlua_ref_global(lstate, -1);
+ LuaRef func = nlua_ref_global(lstate, -1);
- char_u *name = register_cfunc(&nlua_CFunction_func_call,
- &nlua_CFunction_func_free, state);
+ char *name = register_luafunc(func);
lua_pop(lstate, 1); // []
assert(top == lua_gettop(lstate));
@@ -1828,8 +1960,8 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
void nlua_execute_on_key(int c)
{
- char_u buf[NUMBUFLEN];
- size_t buf_len = special_to_buf(c, mod_mask, false, buf);
+ char buf[NUMBUFLEN];
+ size_t buf_len = special_to_buf(c, mod_mask, false, (char_u *)buf);
lua_State *const lstate = global_lstate;
@@ -1845,7 +1977,7 @@ void nlua_execute_on_key(int c)
luaL_checktype(lstate, -1, LUA_TFUNCTION);
// [ vim, vim._on_key, buf ]
- lua_pushlstring(lstate, (const char *)buf, buf_len);
+ lua_pushlstring(lstate, buf, buf_len);
int save_got_int = got_int;
got_int = false; // avoid interrupts when the key typed is Ctrl-C
@@ -1924,6 +2056,9 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
nlua_pushref(lstate, preview ? cmd->uc_preview_luaref : cmd->uc_luaref);
lua_newtable(lstate);
+ lua_pushstring(lstate, cmd->uc_name);
+ lua_setfield(lstate, -2, "name");
+
lua_pushboolean(lstate, eap->forceit == 1);
lua_setfield(lstate, -2, "bang");
@@ -1940,7 +2075,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
// Split args by unescaped whitespace |<f-args>| (nargs dependent)
if (cmd->uc_argt & EX_NOSPC) {
- if ((cmd->uc_argt & EX_NEEDARG) || STRLEN(eap->arg)) {
+ if ((cmd->uc_argt & EX_NEEDARG) || strlen(eap->arg)) {
// For commands where nargs is 1 or "?" and argument is passed, fargs = { args }
lua_rawseti(lstate, -2, 1);
} else {
@@ -1950,7 +2085,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
} else if (eap->args == NULL) {
// For commands with more than one possible argument, split if argument list isn't available.
lua_pop(lstate, 1); // Pop the reference of opts.args
- size_t length = STRLEN(eap->arg);
+ size_t length = strlen(eap->arg);
size_t end = 0;
size_t len = 0;
int i = 1;
@@ -1975,7 +2110,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
}
lua_setfield(lstate, -2, "fargs");
- lua_pushstring(lstate, (const char *)&eap->regname);
+ char reg[2] = { (char)eap->regname, NUL };
+ lua_pushstring(lstate, reg);
lua_setfield(lstate, -2, "reg");
lua_pushinteger(lstate, eap->addr_count);
@@ -1998,7 +2134,7 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
lua_newtable(lstate); // smods table
- lua_pushinteger(lstate, cmdmod.cmod_tab);
+ lua_pushinteger(lstate, cmdmod.cmod_tab - 1);
lua_setfield(lstate, -2, "tab");
lua_pushinteger(lstate, cmdmod.cmod_verbose - 1);
@@ -2019,6 +2155,8 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
lua_pushboolean(lstate, cmdmod.cmod_split & WSP_VERT);
lua_setfield(lstate, -2, "vertical");
+ lua_pushboolean(lstate, cmdmod.cmod_split & WSP_HOR);
+ lua_setfield(lstate, -2, "horizontal");
lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_SILENT);
lua_setfield(lstate, -2, "silent");
lua_pushboolean(lstate, cmdmod.cmod_flags & CMOD_ERRSILENT);
@@ -2113,3 +2251,80 @@ plain:
kv_printf(str, "<Lua %d>", ref);
return str.items;
}
+
+char *nlua_read_secure(const char *path)
+{
+ lua_State *const lstate = global_lstate;
+ const int top = lua_gettop(lstate);
+
+ lua_getglobal(lstate, "vim");
+ lua_getfield(lstate, -1, "secure");
+ lua_getfield(lstate, -1, "read");
+ lua_pushstring(lstate, path);
+ if (nlua_pcall(lstate, 1, 1)) {
+ nlua_error(lstate, _("Error executing vim.secure.read: %.*s"));
+ lua_settop(lstate, top);
+ return NULL;
+ }
+
+ size_t len = 0;
+ const char *contents = lua_tolstring(lstate, -1, &len);
+ char *buf = NULL;
+ if (contents != NULL) {
+ // Add one to include trailing null byte
+ buf = xcalloc(len + 1, sizeof(char));
+ memcpy(buf, contents, len + 1);
+ }
+
+ lua_settop(lstate, top);
+ return buf;
+}
+
+bool nlua_trust(const char *action, const char *path)
+{
+ lua_State *const lstate = global_lstate;
+ const int top = lua_gettop(lstate);
+
+ lua_getglobal(lstate, "vim");
+ lua_getfield(lstate, -1, "secure");
+ lua_getfield(lstate, -1, "trust");
+
+ lua_newtable(lstate);
+ lua_pushstring(lstate, "action");
+ lua_pushstring(lstate, action);
+ lua_settable(lstate, -3);
+ if (path == NULL) {
+ lua_pushstring(lstate, "bufnr");
+ lua_pushnumber(lstate, 0);
+ lua_settable(lstate, -3);
+ } else {
+ lua_pushstring(lstate, "path");
+ lua_pushstring(lstate, path);
+ lua_settable(lstate, -3);
+ }
+
+ if (nlua_pcall(lstate, 1, 2)) {
+ nlua_error(lstate, _("Error executing vim.secure.trust: %.*s"));
+ lua_settop(lstate, top);
+ return false;
+ }
+
+ bool success = lua_toboolean(lstate, -2);
+ const char *msg = lua_tostring(lstate, -1);
+ if (msg != NULL) {
+ if (success) {
+ if (strcmp(action, "allow") == 0) {
+ smsg("Allowed \"%s\" in trust database.", msg);
+ } else if (strcmp(action, "deny") == 0) {
+ smsg("Denied \"%s\" in trust database.", msg);
+ } else if (strcmp(action, "remove") == 0) {
+ smsg("Removed \"%s\" from trust database.", msg);
+ }
+ } else {
+ semsg(e_trustfile, msg);
+ }
+ }
+
+ lua_settop(lstate, top);
+ return success;
+}