aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2023-01-03 02:54:53 +0100
committerJustin M. Keyes <justinkz@gmail.com>2023-01-05 17:10:02 +0100
commitf43de742e881e54a3602e00c8c247cecca65a266 (patch)
treeb53c6c40989690a37a2bd278587aaba64e7ff332
parentadef308a5925a3b967af3bd7c598074e5b6cae18 (diff)
downloadrneovim-f43de742e881e54a3602e00c8c247cecca65a266.tar.gz
rneovim-f43de742e881e54a3602e00c8c247cecca65a266.tar.bz2
rneovim-f43de742e881e54a3602e00c8c247cecca65a266.zip
feat(lua): execute stdin ("-") as Lua
-rw-r--r--runtime/doc/starting.txt7
-rw-r--r--src/nvim/README.md6
-rw-r--r--src/nvim/lua/executor.c57
-rw-r--r--src/nvim/main.c2
-rw-r--r--test/functional/core/startup_spec.lua58
5 files changed, 102 insertions, 28 deletions
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 8dd083e4a3..fa9e23eb00 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -236,9 +236,10 @@ argument.
< This loads Lua module "bar" before executing "foo.lua": >
nvim +"lua require('bar')" -l foo.lua
<
- User |config| is skipped unless |-u| was given.
- User |shada| is skipped unless |-i| was given.
- Swap file is skipped (like |-n|).
+ Skips user |config| unless |-u| was given.
+ Disables plugins unless 'loadplugins' was set.
+ Disables |shada| unless |-i| was given.
+ Disables swapfile (like |-n|).
*-b*
-b Binary mode. File I/O will only recognize <NL> to separate
diff --git a/src/nvim/README.md b/src/nvim/README.md
index e710c3ef58..6876227e48 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -18,6 +18,12 @@ The source files use extensions to hint about their purpose.
- `*.h.generated.h` - exported functions’ declarations.
- `*.c.generated.h` - static functions’ declarations.
+Common structures
+-----------------
+
+- StringBuilder
+- kvec or garray.c for dynamic lists / vectors (use StringBuilder for strings)
+
Logs
----
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 4b08603dd0..b7844363c5 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -335,7 +335,7 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate)
/// @see https://github.com/premake/premake-core/blob/1c1304637f4f5e50ba8c57aae8d1d80ec3b7aaf2/src/host/premake.c#L563-L594
///
/// @returns number of args
-int nlua_set_argv(char **argv, int argc, int lua_arg0)
+int nlua_init_argv(char **argv, int argc, int lua_arg0)
{
lua_State *const L = global_lstate;
lua_newtable(L); // _G.arg
@@ -1711,21 +1711,62 @@ void ex_luafile(exarg_T *const eap)
nlua_exec_file((const char *)eap->arg);
}
-/// Executes 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 was overridden in the user's 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 {
+ int error;
+ int stdin_dup_fd;
+ if (stdin_fd > 0) {
+ stdin_dup_fd = stdin_fd;
+ } else {
+ stdin_dup_fd = os_dup(STDIN_FILENO);
+#ifdef MSWIN
+ // Replace the original stdin with the console input handle.
+ os_replace_stdin_to_conin();
+#endif
+ }
+ FileDescriptor *const stdin_dup = file_open_fd_new(&error, stdin_dup_fd,
+ kFileReadOnly|kFileNonBlocking);
+ assert(stdin_dup != NULL);
+
+ 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;
+ }
+ 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"));
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 616cf1b4b6..f0ce26d1bc 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -280,7 +280,7 @@ int main(int argc, char **argv)
command_line_scan(&params);
nlua_init();
- nlua_set_argv(argv, argc, params.lua_arg0);
+ nlua_init_argv(argv, argc, params.lua_arg0);
TIME_MSG("init lua interpreter");
if (embedded_mode) {
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 455de08548..d7e64c6b54 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -88,18 +88,18 @@ describe('startup', function()
end)
describe('-l Lua', function()
- local function assert_l_out(expected, nvim_args, lua_args)
- local args = { nvim_prog, '--clean' }
+ local function assert_l_out(expected, nvim_args, lua_args, script, input)
+ local args = { nvim_prog }
vim.list_extend(args, nvim_args or {})
- vim.list_extend(args, { '-l', 'test/functional/fixtures/startup.lua' })
+ vim.list_extend(args, { '-l', (script or 'test/functional/fixtures/startup.lua') })
vim.list_extend(args, lua_args or {})
- local out = funcs.system(args):gsub('\r\n', '\n')
+ local out = funcs.system(args, input):gsub('\r\n', '\n')
return eq(dedent(expected), out)
end
it('failure modes', function()
- -- nvim -l <missing file>
- matches('nvim: Argument missing after: "%-l"', funcs.system({ nvim_prog, '-l' }))
+ -- nvim -l <empty>
+ matches('nvim%.?e?x?e?: Argument missing after: "%-l"', funcs.system({ nvim_prog, '-l' }))
eq(1, eval('v:shell_error'))
end)
@@ -107,7 +107,7 @@ describe('startup', function()
-- nvim -l foo.lua -arg1 -- a b c
assert_l_out([[
bufs:
- nvim args: 8
+ nvim args: 7
lua args: { "-arg1", "--exitcode", "73", "--arg2" }]],
{},
{ '-arg1', "--exitcode", "73", '--arg2' }
@@ -115,18 +115,35 @@ describe('startup', function()
eq(73, eval('v:shell_error'))
end)
- it('Lua error sets Nvim exitcode', function()
+ it('Lua-error sets Nvim exitcode', function()
eq(0, eval('v:shell_error'))
matches('E5113: .* my pearls!!',
funcs.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' }))
eq(1, eval('v:shell_error'))
+ matches('E5113: .* %[string "error%("whoa"%)"%]:1: whoa',
+ funcs.system({ nvim_prog, '-l', '-' }, 'error("whoa")'))
+ eq(1, eval('v:shell_error'))
+ end)
+
+ it('executes stdin "-"', function()
+ assert_l_out('args=2 whoa',
+ nil,
+ { 'arg1', 'arg 2' },
+ '-',
+ "print(('args=%d %s'):format(#_G.arg, 'whoa'))")
+ assert_l_out('biiig input: 1000042',
+ nil,
+ nil,
+ '-',
+ ('print("biiig input: "..("%s"):len())'):format(string.rep('x', (1000 * 1000) + 42)))
+ eq(0, eval('v:shell_error'))
end)
it('sets _G.arg', function()
-- nvim -l foo.lua -arg1 -- a b c
assert_l_out([[
bufs:
- nvim args: 7
+ nvim args: 6
lua args: { "-arg1", "--arg2", "arg3" }]],
{},
{ '-arg1', '--arg2', 'arg3' }
@@ -136,7 +153,7 @@ describe('startup', function()
-- nvim -l foo.lua --
assert_l_out([[
bufs:
- nvim args: 5
+ nvim args: 4
lua args: { "--" }]],
{},
{ '--' }
@@ -146,7 +163,7 @@ describe('startup', function()
-- nvim file1 file2 -l foo.lua -arg1 -- file3 file4
assert_l_out([[
bufs: file1 file2
- nvim args: 11
+ nvim args: 10
lua args: { "-arg1", "arg 2", "--", "file3", "file4" }]],
{ 'file1', 'file2', },
{ '-arg1', 'arg 2', '--', 'file3', 'file4' }
@@ -156,7 +173,7 @@ describe('startup', function()
-- nvim file1 file2 -l foo.lua -arg1 --
assert_l_out([[
bufs: file1 file2
- nvim args: 8
+ nvim args: 7
lua args: { "-arg1", "--" }]],
{ 'file1', 'file2', },
{ '-arg1', '--' }
@@ -166,7 +183,7 @@ describe('startup', function()
-- nvim -l foo.lua <vim args>
assert_l_out([[
bufs:
- nvim args: 6
+ nvim args: 5
lua args: { "-c", "set wrap?" }]],
{},
{ '-c', 'set wrap?' }
@@ -180,13 +197,22 @@ describe('startup', function()
wrap
bufs:
- nvim args: 8
+ nvim args: 7
lua args: { "-c", "set wrap?" }]],
{ '-c', 'set wrap?' },
{ '-c', 'set wrap?' }
)
eq(0, eval('v:shell_error'))
end)
+
+ it('disables swapfile/shada/config/plugins', function()
+ assert_l_out('updatecount=0 shadafile=NONE loadplugins=false scriptnames=1',
+ nil,
+ nil,
+ '-',
+ [[print(('updatecount=%d shadafile=%s loadplugins=%s scriptnames=%d'):format(
+ vim.o.updatecount, vim.o.shadafile, tostring(vim.o.loadplugins), math.max(1, #vim.fn.split(vim.fn.execute('scriptnames'),'\n'))))]])
+ end)
end)
it('pipe at both ends: has("ttyin")==0 has("ttyout")==0', function()
@@ -375,11 +401,11 @@ describe('startup', function()
it('-es/-Es disables swapfile, user config #8540', function()
for _,arg in ipairs({'-es', '-Es'}) do
local out = funcs.system({nvim_prog, arg,
- '+set swapfile? updatecount? shada?',
+ '+set swapfile? updatecount? shadafile?',
"+put =execute('scriptnames')", '+%print'})
local line1 = string.match(out, '^.-\n')
-- updatecount=0 means swapfile was disabled.
- eq(" swapfile updatecount=0 shada=!,'100,<50,s10,h\n", line1)
+ eq(" swapfile updatecount=0 shadafile=\n", line1)
-- Standard plugins were loaded, but not user config.
eq('health.vim', string.match(out, 'health.vim'))
eq(nil, string.match(out, 'init.vim'))