mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(lua): execute stdin ("-") as Lua
This commit is contained in:
parent
adef308a59
commit
f43de742e8
@ -236,9 +236,10 @@ argument.
|
|||||||
< This loads Lua module "bar" before executing "foo.lua": >
|
< This loads Lua module "bar" before executing "foo.lua": >
|
||||||
nvim +"lua require('bar')" -l foo.lua
|
nvim +"lua require('bar')" -l foo.lua
|
||||||
<
|
<
|
||||||
User |config| is skipped unless |-u| was given.
|
Skips user |config| unless |-u| was given.
|
||||||
User |shada| is skipped unless |-i| was given.
|
Disables plugins unless 'loadplugins' was set.
|
||||||
Swap file is skipped (like |-n|).
|
Disables |shada| unless |-i| was given.
|
||||||
|
Disables swapfile (like |-n|).
|
||||||
|
|
||||||
*-b*
|
*-b*
|
||||||
-b Binary mode. File I/O will only recognize <NL> to separate
|
-b Binary mode. File I/O will only recognize <NL> to separate
|
||||||
|
@ -18,6 +18,12 @@ The source files use extensions to hint about their purpose.
|
|||||||
- `*.h.generated.h` - exported functions’ declarations.
|
- `*.h.generated.h` - exported functions’ declarations.
|
||||||
- `*.c.generated.h` - static functions’ declarations.
|
- `*.c.generated.h` - static functions’ declarations.
|
||||||
|
|
||||||
|
Common structures
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- StringBuilder
|
||||||
|
- kvec or garray.c for dynamic lists / vectors (use StringBuilder for strings)
|
||||||
|
|
||||||
Logs
|
Logs
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -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
|
/// @see https://github.com/premake/premake-core/blob/1c1304637f4f5e50ba8c57aae8d1d80ec3b7aaf2/src/host/premake.c#L563-L594
|
||||||
///
|
///
|
||||||
/// @returns number of args
|
/// @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_State *const L = global_lstate;
|
||||||
lua_newtable(L); // _G.arg
|
lua_newtable(L); // _G.arg
|
||||||
@ -1711,21 +1711,62 @@ void ex_luafile(exarg_T *const eap)
|
|||||||
nlua_exec_file((const char *)eap->arg);
|
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
|
/// Calls the Lua `loadfile` global as opposed to `luaL_loadfile` in case `loadfile` was overridden
|
||||||
/// in case loadfile was overridden in the user's environment.
|
/// 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)
|
bool nlua_exec_file(const char *path)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
lua_State *const lstate = global_lstate;
|
lua_State *const lstate = global_lstate;
|
||||||
|
if (!strequal(path, "-")) {
|
||||||
lua_getglobal(lstate, "loadfile");
|
lua_getglobal(lstate, "loadfile");
|
||||||
lua_pushstring(lstate, path);
|
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, "loadstring");
|
||||||
|
lua_pushstring(lstate, sb.items);
|
||||||
|
kv_destroy(sb);
|
||||||
|
}
|
||||||
|
|
||||||
if (nlua_pcall(lstate, 1, 2)) {
|
if (nlua_pcall(lstate, 1, 2)) {
|
||||||
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
|
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
|
||||||
|
@ -280,7 +280,7 @@ int main(int argc, char **argv)
|
|||||||
command_line_scan(¶ms);
|
command_line_scan(¶ms);
|
||||||
|
|
||||||
nlua_init();
|
nlua_init();
|
||||||
nlua_set_argv(argv, argc, params.lua_arg0);
|
nlua_init_argv(argv, argc, params.lua_arg0);
|
||||||
TIME_MSG("init lua interpreter");
|
TIME_MSG("init lua interpreter");
|
||||||
|
|
||||||
if (embedded_mode) {
|
if (embedded_mode) {
|
||||||
|
@ -88,18 +88,18 @@ describe('startup', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
describe('-l Lua', function()
|
describe('-l Lua', function()
|
||||||
local function assert_l_out(expected, nvim_args, lua_args)
|
local function assert_l_out(expected, nvim_args, lua_args, script, input)
|
||||||
local args = { nvim_prog, '--clean' }
|
local args = { nvim_prog }
|
||||||
vim.list_extend(args, nvim_args or {})
|
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 {})
|
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)
|
return eq(dedent(expected), out)
|
||||||
end
|
end
|
||||||
|
|
||||||
it('failure modes', function()
|
it('failure modes', function()
|
||||||
-- nvim -l <missing file>
|
-- nvim -l <empty>
|
||||||
matches('nvim: Argument missing after: "%-l"', funcs.system({ nvim_prog, '-l' }))
|
matches('nvim%.?e?x?e?: Argument missing after: "%-l"', funcs.system({ nvim_prog, '-l' }))
|
||||||
eq(1, eval('v:shell_error'))
|
eq(1, eval('v:shell_error'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ describe('startup', function()
|
|||||||
-- nvim -l foo.lua -arg1 -- a b c
|
-- nvim -l foo.lua -arg1 -- a b c
|
||||||
assert_l_out([[
|
assert_l_out([[
|
||||||
bufs:
|
bufs:
|
||||||
nvim args: 8
|
nvim args: 7
|
||||||
lua args: { "-arg1", "--exitcode", "73", "--arg2" }]],
|
lua args: { "-arg1", "--exitcode", "73", "--arg2" }]],
|
||||||
{},
|
{},
|
||||||
{ '-arg1', "--exitcode", "73", '--arg2' }
|
{ '-arg1', "--exitcode", "73", '--arg2' }
|
||||||
@ -115,18 +115,35 @@ describe('startup', function()
|
|||||||
eq(73, eval('v:shell_error'))
|
eq(73, eval('v:shell_error'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('Lua error sets Nvim exitcode', function()
|
it('Lua-error sets Nvim exitcode', function()
|
||||||
eq(0, eval('v:shell_error'))
|
eq(0, eval('v:shell_error'))
|
||||||
matches('E5113: .* my pearls!!',
|
matches('E5113: .* my pearls!!',
|
||||||
funcs.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' }))
|
funcs.system({ nvim_prog, '-l', 'test/functional/fixtures/startup-fail.lua' }))
|
||||||
eq(1, eval('v:shell_error'))
|
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)
|
end)
|
||||||
|
|
||||||
it('sets _G.arg', function()
|
it('sets _G.arg', function()
|
||||||
-- nvim -l foo.lua -arg1 -- a b c
|
-- nvim -l foo.lua -arg1 -- a b c
|
||||||
assert_l_out([[
|
assert_l_out([[
|
||||||
bufs:
|
bufs:
|
||||||
nvim args: 7
|
nvim args: 6
|
||||||
lua args: { "-arg1", "--arg2", "arg3" }]],
|
lua args: { "-arg1", "--arg2", "arg3" }]],
|
||||||
{},
|
{},
|
||||||
{ '-arg1', '--arg2', 'arg3' }
|
{ '-arg1', '--arg2', 'arg3' }
|
||||||
@ -136,7 +153,7 @@ describe('startup', function()
|
|||||||
-- nvim -l foo.lua --
|
-- nvim -l foo.lua --
|
||||||
assert_l_out([[
|
assert_l_out([[
|
||||||
bufs:
|
bufs:
|
||||||
nvim args: 5
|
nvim args: 4
|
||||||
lua args: { "--" }]],
|
lua args: { "--" }]],
|
||||||
{},
|
{},
|
||||||
{ '--' }
|
{ '--' }
|
||||||
@ -146,7 +163,7 @@ describe('startup', function()
|
|||||||
-- nvim file1 file2 -l foo.lua -arg1 -- file3 file4
|
-- nvim file1 file2 -l foo.lua -arg1 -- file3 file4
|
||||||
assert_l_out([[
|
assert_l_out([[
|
||||||
bufs: file1 file2
|
bufs: file1 file2
|
||||||
nvim args: 11
|
nvim args: 10
|
||||||
lua args: { "-arg1", "arg 2", "--", "file3", "file4" }]],
|
lua args: { "-arg1", "arg 2", "--", "file3", "file4" }]],
|
||||||
{ 'file1', 'file2', },
|
{ 'file1', 'file2', },
|
||||||
{ '-arg1', 'arg 2', '--', 'file3', 'file4' }
|
{ '-arg1', 'arg 2', '--', 'file3', 'file4' }
|
||||||
@ -156,7 +173,7 @@ describe('startup', function()
|
|||||||
-- nvim file1 file2 -l foo.lua -arg1 --
|
-- nvim file1 file2 -l foo.lua -arg1 --
|
||||||
assert_l_out([[
|
assert_l_out([[
|
||||||
bufs: file1 file2
|
bufs: file1 file2
|
||||||
nvim args: 8
|
nvim args: 7
|
||||||
lua args: { "-arg1", "--" }]],
|
lua args: { "-arg1", "--" }]],
|
||||||
{ 'file1', 'file2', },
|
{ 'file1', 'file2', },
|
||||||
{ '-arg1', '--' }
|
{ '-arg1', '--' }
|
||||||
@ -166,7 +183,7 @@ describe('startup', function()
|
|||||||
-- nvim -l foo.lua <vim args>
|
-- nvim -l foo.lua <vim args>
|
||||||
assert_l_out([[
|
assert_l_out([[
|
||||||
bufs:
|
bufs:
|
||||||
nvim args: 6
|
nvim args: 5
|
||||||
lua args: { "-c", "set wrap?" }]],
|
lua args: { "-c", "set wrap?" }]],
|
||||||
{},
|
{},
|
||||||
{ '-c', 'set wrap?' }
|
{ '-c', 'set wrap?' }
|
||||||
@ -180,13 +197,22 @@ describe('startup', function()
|
|||||||
wrap
|
wrap
|
||||||
|
|
||||||
bufs:
|
bufs:
|
||||||
nvim args: 8
|
nvim args: 7
|
||||||
lua args: { "-c", "set wrap?" }]],
|
lua args: { "-c", "set wrap?" }]],
|
||||||
{ '-c', 'set wrap?' },
|
{ '-c', 'set wrap?' },
|
||||||
{ '-c', 'set wrap?' }
|
{ '-c', 'set wrap?' }
|
||||||
)
|
)
|
||||||
eq(0, eval('v:shell_error'))
|
eq(0, eval('v:shell_error'))
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
it('pipe at both ends: has("ttyin")==0 has("ttyout")==0', function()
|
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()
|
it('-es/-Es disables swapfile, user config #8540', function()
|
||||||
for _,arg in ipairs({'-es', '-Es'}) do
|
for _,arg in ipairs({'-es', '-Es'}) do
|
||||||
local out = funcs.system({nvim_prog, arg,
|
local out = funcs.system({nvim_prog, arg,
|
||||||
'+set swapfile? updatecount? shada?',
|
'+set swapfile? updatecount? shadafile?',
|
||||||
"+put =execute('scriptnames')", '+%print'})
|
"+put =execute('scriptnames')", '+%print'})
|
||||||
local line1 = string.match(out, '^.-\n')
|
local line1 = string.match(out, '^.-\n')
|
||||||
-- updatecount=0 means swapfile was disabled.
|
-- 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.
|
-- Standard plugins were loaded, but not user config.
|
||||||
eq('health.vim', string.match(out, 'health.vim'))
|
eq('health.vim', string.match(out, 'health.vim'))
|
||||||
eq(nil, string.match(out, 'init.vim'))
|
eq(nil, string.match(out, 'init.vim'))
|
||||||
|
Loading…
Reference in New Issue
Block a user