aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-02-26 15:19:10 +0100
committerbfredl <bjorn.linse@gmail.com>2023-01-31 13:53:22 +0100
commitd6d6ab3f8e77d54c8030c0c18f17d3c72ac4445c (patch)
tree9b9983b37a81b55e810bd4998a357fca490fcf0f
parentfacbb11e050186a13aa5451591f3c53b012f5566 (diff)
downloadrneovim-d6d6ab3f8e77d54c8030c0c18f17d3c72ac4445c.tar.gz
rneovim-d6d6ab3f8e77d54c8030c0c18f17d3c72ac4445c.tar.bz2
rneovim-d6d6ab3f8e77d54c8030c0c18f17d3c72ac4445c.zip
feat(lua): low-level interpreter mode (nvim -ll)
-rw-r--r--runtime/doc/starting.txt8
-rw-r--r--runtime/lua/vim/_init_packages.lua9
-rw-r--r--src/nvim/lua/executor.c67
-rw-r--r--src/nvim/main.c16
4 files changed, 77 insertions, 23 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 179bacdb24..5e0718c3bb 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -239,6 +239,14 @@ argument.
Disables |shada| unless |-i| was given.
Disables swapfile (like |-n|).
+ *-ll*
+-ll {script} [args]
+ Execute a lua script, similarly to |-l|, but the editor is not
+ initialized. This gives a lua enviroment similar to a worker
+ thread. See |lua-loop-threading|.
+
+ Unlike `-l` no prior arguments are allowed.
+
*-b*
-b Binary mode. File I/O will only recognize <NL> to separate
lines. The 'expandtab' option will be reset. The 'textwidth'
diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua
index 0c4ee8636d..e3a442af5e 100644
--- a/runtime/lua/vim/_init_packages.lua
+++ b/runtime/lua/vim/_init_packages.lua
@@ -42,8 +42,11 @@ function vim._load_package(name)
return nil
end
--- Insert vim._load_package after the preloader at position 2
-table.insert(package.loaders, 2, vim._load_package)
+-- TODO(bfredl): dedicated state for this?
+if vim.api then
+ -- Insert vim._load_package after the preloader at position 2
+ table.insert(package.loaders, 2, vim._load_package)
+end
-- builtin functions which always should be available
require('vim.shared')
@@ -78,6 +81,6 @@ function vim.empty_dict()
end
-- only on main thread: functions for interacting with editor state
-if not vim.is_thread() then
+if vim.api and not vim.is_thread() then
require('vim._editor')
end
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 5ffd90fddd..d144a5ae23 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -64,6 +64,7 @@
#include "nvim/window.h"
static int in_fast_callback = 0;
+static bool in_script = false;
// Initialized in nlua_init().
static lua_State *global_lstate = NULL;
@@ -133,8 +134,13 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
str = lua_tolstring(lstate, -1, &len);
}
- msg_ext_set_kind("lua_error");
- semsg_multiline(msg, (int)len, str);
+ if (in_script) {
+ os_errmsg(str);
+ os_errmsg("\n");
+ } else {
+ msg_ext_set_kind("lua_error");
+ semsg_multiline(msg, (int)len, str);
+ }
lua_pop(lstate, 1);
}
@@ -534,7 +540,7 @@ int nlua_get_global_ref_count(void)
return nlua_global_refs->ref_count;
}
-static void nlua_common_vim_init(lua_State *lstate, bool is_thread)
+static void nlua_common_vim_init(lua_State *lstate, bool is_thread, bool is_standalone)
FUNC_ATTR_NONNULL_ARG(1)
{
nlua_ref_state_t *ref_state = nlua_new_ref_state(lstate, is_thread);
@@ -567,7 +573,9 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread)
lua_setfield(lstate, -2, "_empty_dict_mt");
// vim.loop
- if (is_thread) {
+ if (is_standalone) {
+ // do nothing, use libluv like in a standalone interpreter
+ } else if (is_thread) {
luv_set_callback(lstate, nlua_luv_thread_cb_cfpcall);
luv_set_thread(lstate, nlua_luv_thread_cfpcall);
luv_set_cthread(lstate, nlua_luv_thread_cfcpcall);
@@ -606,7 +614,7 @@ static int nlua_module_preloader(lua_State *lstate)
return 1;
}
-static bool nlua_init_packages(lua_State *lstate)
+static bool nlua_init_packages(lua_State *lstate, bool is_standalone)
FUNC_ATTR_NONNULL_ALL
{
// put builtin packages in preload
@@ -618,7 +626,7 @@ static bool nlua_init_packages(lua_State *lstate)
lua_pushcclosure(lstate, nlua_module_preloader, 1); // [package, preload, cclosure]
lua_setfield(lstate, -2, def.name); // [package, preload]
- if (nlua_disable_preload && strequal(def.name, "vim.inspect")) {
+ if ((nlua_disable_preload && !is_standalone) && strequal(def.name, "vim.inspect")) {
break;
}
}
@@ -769,7 +777,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_ui_detach);
lua_setfield(lstate, -2, "ui_detach");
- nlua_common_vim_init(lstate, false);
+ nlua_common_vim_init(lstate, false, false);
// patch require() (only for --startuptime)
if (time_fd != NULL) {
@@ -788,7 +796,7 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setglobal(lstate, "vim");
- if (!nlua_init_packages(lstate)) {
+ if (!nlua_init_packages(lstate, false)) {
return false;
}
@@ -824,9 +832,28 @@ void nlua_init(char **argv, int argc, int lua_arg0)
static lua_State *nlua_thread_acquire_vm(void)
{
+ return nlua_init_state(true);
+}
+
+void nlua_run_script(char **argv, int argc, int lua_arg0)
+ FUNC_ATTR_NORETURN
+{
+ in_script = true;
+ global_lstate = nlua_init_state(false);
+ luv_set_thread_cb(nlua_thread_acquire_vm, nlua_common_free_all_mem);
+ nlua_init_argv(global_lstate, argv, argc, lua_arg0);
+ bool lua_ok = nlua_exec_file(argv[lua_arg0 - 1]);
+#ifdef EXITFREE
+ nlua_free_all_mem();
+#endif
+ exit(lua_ok ? 0 : 1);
+}
+
+lua_State *nlua_init_state(bool thread)
+{
// If it is called from the main thread, it will attempt to rebuild the cache.
const uv_thread_t self = uv_thread_self();
- if (uv_thread_equal(&main_thread, &self)) {
+ if (!in_script && uv_thread_equal(&main_thread, &self)) {
runtime_search_path_validate();
}
@@ -835,9 +862,11 @@ static lua_State *nlua_thread_acquire_vm(void)
// Add in the lua standard libraries
luaL_openlibs(lstate);
- // print
- lua_pushcfunction(lstate, &nlua_print);
- lua_setglobal(lstate, "print");
+ if (!in_script) {
+ // print
+ lua_pushcfunction(lstate, &nlua_print);
+ lua_setglobal(lstate, "print");
+ }
lua_pushinteger(lstate, 0);
lua_setfield(lstate, LUA_REGISTRYINDEX, "nlua.refcount");
@@ -845,18 +874,20 @@ static lua_State *nlua_thread_acquire_vm(void)
// vim
lua_newtable(lstate);
- nlua_common_vim_init(lstate, true);
+ nlua_common_vim_init(lstate, thread, in_script);
nlua_state_add_stdlib(lstate, true);
- lua_createtable(lstate, 0, 0);
- lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime);
- lua_setfield(lstate, -2, "nvim__get_runtime");
- lua_setfield(lstate, -2, "api");
+ if (!in_script) {
+ lua_createtable(lstate, 0, 0);
+ lua_pushcfunction(lstate, nlua_thr_api_nvim__get_runtime);
+ lua_setfield(lstate, -2, "nvim__get_runtime");
+ lua_setfield(lstate, -2, "api");
+ }
lua_setglobal(lstate, "vim");
- nlua_init_packages(lstate);
+ nlua_init_packages(lstate, in_script);
lua_getglobal(lstate, "package");
lua_getfield(lstate, -1, "loaded");
diff --git a/src/nvim/main.c b/src/nvim/main.c
index bbe877356d..8df82c710a 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -239,6 +239,14 @@ int main(int argc, char **argv)
argv0 = argv[0];
+ if (argc > 1 && STRICMP(argv[1], "-ll") == 0) {
+ if (argc == 2) {
+ print_mainerr(err_arg_missing, argv[1]);
+ exit(1);
+ }
+ nlua_run_script(argv, argc, 3);
+ }
+
char *fname = NULL; // file name from command line
mparm_T params; // various parameters passed between
// main() and other functions.
@@ -2111,6 +2119,12 @@ static int execute_env(char *env)
static void mainerr(const char *errstr, const char *str)
FUNC_ATTR_NORETURN
{
+ print_mainerr(errstr, str);
+ os_exit(1);
+}
+
+static void print_mainerr(const char *errstr, const char *str)
+{
char *prgname = path_tail(argv0);
signal_stop(); // kill us with CTRL-C here, if you like
@@ -2126,8 +2140,6 @@ static void mainerr(const char *errstr, const char *str)
os_errmsg(_("\nMore info with \""));
os_errmsg(prgname);
os_errmsg(" -h\"\n");
-
- os_exit(1);
}
/// Prints version information for "nvim -v" or "nvim --version".