feat(lua): send "--" literally to Lua "-l" script

Problem:
When "-l" is followed by "--", we stop sending args to the Lua script
and treat "--" in the usual way. This was for flexibility but didn't
have a strong use-case, and has these problems:
- prevents Lua "-l" scripts from handling "--" in their own way.
- complicates the startup logic (must call nlua_init before command_line_scan)

Solution:
Don't treat "--" specially if it follows "-l".
This commit is contained in:
Justin M. Keyes 2023-01-01 03:14:13 +01:00
parent 599e1d019a
commit 45549f031e
7 changed files with 74 additions and 53 deletions

View File

@ -32,7 +32,7 @@ filename One or more file names. The first one will be the current
an option, precede the arglist with "--", e.g.: >
nvim -- -filename
< All arguments after "--" are interpreted as file names, no
other options or "+command" argument can follow.
other options or "+command" arguments can follow.
*--*
`-` Alias for stdin (standard input).
@ -143,9 +143,9 @@ argument.
these commands, independently from "-c" commands.
*-S*
-S [file] Vimscript or Lua (".lua") [file] will be |:source|d after the
first file has been read or "Session.vim" if [file] is not
given. Equivalent to: >
-S [file] Executes Vimscript or Lua (".lua") [file] after the first file
has been read. See also |:source|. If [file] is not given,
defaults to "Session.vim". Equivalent to: >
-c "source {file}"
< Can be repeated like "-c", subject to the same limit of 10
"-c" arguments. {file} cannot start with a "-".
@ -190,8 +190,9 @@ argument.
-E reads stdin as text (into buffer 1).
-es *-es* *-Es* *-s-ex* *silent-mode*
-Es Silent mode (no UI), for scripting. Unrelated to |-s|.
Disables most prompts, messages, warnings and errors.
-Es Script mode, aka "silent mode", aka "batch mode". No UI,
disables most prompts and messages. Unrelated to |-s|.
See also |-S| to run script files.
-es reads/executes stdin as Ex commands. >
printf "put ='foo'\n%%print\n" | nvim -es
@ -215,16 +216,22 @@ argument.
*-l*
-l {script} [args]
Executes Lua {script} file and exits. All [args] (up to "--"
|---|) are treated as {script} args, not Nvim args: by Lua
convention they are set in the `_G.arg` global table. *lua-args*
On {script} error, Nvim exits with code 1.
Executes Lua {script} non-interactively (no UI) with optional
[args] after processing any preceding Nvim |cli-arguments|,
then exits. See |-S| to run multiple Lua scripts without args,
or in an interactive session.
*lua-args*
All [args] are treated as {script} arguments and passed
literally to Lua (in the conventional `_G.arg` global table),
thus "-l" ends processing of Nvim arguments.
Exits with code 1 on Lua error.
Sets 'verbose' to 1 (like "-V1"), so Lua `print()` writes to
output.
Any |cli-arguments| before "-l" are processed before executing
{script}. For example this quits before executing "foo.lua": >
Arguments before "-l" are processed before executing {script}.
This example quits before executing "foo.lua": >
nvim +q -l foo.lua
< This loads Lua module "bar" before executing "foo.lua": >
nvim +"lua require('bar')" -l foo.lua
@ -256,7 +263,7 @@ argument.
-V[N]{file}
Like -V and sets 'verbosefile' to {file} (must not start with
a digit). Messages are not displayed; instead they are
a digit). Messages are not displayed, instead they are
written to {file}.
Example: >
nvim -V20vimlog

View File

@ -122,9 +122,6 @@ modifications.
.It Fl b
Binary mode.
.Ic ":help edit-binary"
.It Fl l
Lisp mode.
Sets the 'lisp' and 'showmatch' options.
.It Fl A
Arabic mode.
Sets the 'arabic' option.
@ -144,7 +141,7 @@ is specified, append messages to
instead of printing them.
.Ic ":help 'verbose'"
.It Fl D
Debug mode for VimL (Vim script).
Vimscript debug mode.
Started when executing the first command from a script.
:help debug-mode
.It Fl n
@ -268,10 +265,26 @@ but execute
before processing any vimrc.
Up to 10 instances of these can be used independently from instances of
.Fl c .
.It Fl l Ar script Op Ar args
Execute Lua
.Ar script
with optional
.Op Ar args
after processing any preceding Nvim startup arguments.
All
.Op Ar args
are treated as script arguments and are passed literally to Lua, that is,
.Fl l
stops processing of Nvim arguments.
.Ic ":help -l"
.It Fl S Op Ar session
Source
Execute
.Ar session
after the first file argument has been read.
after the first file argument has been read. If
.Ar session
filename ends with
.Pa .lua
it is executed as Lua instead of Vimscript.
Equivalent to
.Cm -c \(dqsource session\(dq .
.Ar session

View File

@ -323,32 +323,28 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate)
return 1;
}
/// Copies all args into the Lua `arg` global.
/// Copies args starting at `lua_arg0` into the Lua `arg` global.
///
/// Example:
/// nvim -l foo.lua -- -e "sin=math.sin" script a b
/// nvim -l foo.lua --arg1 --arg2
///
/// @note `lua` CLI sets _negative_ `arg` indices to the arguments upto "-e".
///
/// @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 (stops at "--")
int nlua_set_argv(char **argv, int argc)
/// @returns number of args
int nlua_set_argv(char **argv, int argc, int lua_arg0)
{
lua_State *const L = global_lstate;
lua_newtable(L);
lua_newtable(L); // _G.arg
int i = 0;
for (; i < argc; i++) {
if (strequal("--", argv[i])) {
i--;
break;
}
lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i + 1);
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] = "arg1"
}
lua_setglobal(L, "arg");
return i + 1;
return i;
}
static void nlua_schedule_event(void **argv)

View File

@ -275,14 +275,14 @@ int main(int argc, char **argv)
// Check if we have an interactive window.
check_and_set_isatty(&params);
// TODO: should we try to keep param scan before this?
nlua_init();
TIME_MSG("init lua interpreter");
// Process the command line arguments. File names are put in the global
// argument list "global_alist".
command_line_scan(&params);
nlua_init();
nlua_set_argv(argv, argc, params.lua_arg0);
TIME_MSG("init lua interpreter");
if (embedded_mode) {
const char *err;
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
@ -1318,14 +1318,9 @@ static void command_line_scan(mparm_T *parmp)
}
parmp->luaf = argv[0];
argc--;
argv++;
// Lua args after "-l <file>" (upto "--").
int l_argc = nlua_set_argv(argv, argc);
assert(l_argc >= 0);
argc = argc - l_argc;
if (argc > 0) { // Found "--".
argv = argv + l_argc;
had_minmin = true;
if (argc > 0) { // Lua args after "-l <file>".
parmp->lua_arg0 = parmp->argc - argc;
argc = 0;
}
break;
@ -1438,6 +1433,7 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
paramp->server_addr = NULL;
paramp->remote = 0;
paramp->luaf = NULL;
paramp->lua_arg0 = -1;
}
/// Initialize global startuptime file if "--startuptime" passed as an argument.

View File

@ -24,6 +24,7 @@ typedef struct {
int n_pre_commands; // no. of commands from --cmd
char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
char *luaf; // Lua script filename from "-l"
int lua_arg0; // Lua script args start index.
int edit_type; // type of editing to do
char *tagname; // tag from -t argument

View File

@ -107,7 +107,8 @@ describe('startup', function()
-- nvim -l foo.lua -arg1 -- a b c
assert_l_out([[
bufs:
args: { "-arg1", "--exitcode", "73", "--arg2" }]],
nvim args: 8
lua args: { "-arg1", "--exitcode", "73", "--arg2" }]],
{},
{ '-arg1', "--exitcode", "73", '--arg2' }
)
@ -118,7 +119,8 @@ describe('startup', function()
-- nvim -l foo.lua -arg1 -- a b c
assert_l_out([[
bufs:
args: { "-arg1", "--arg2", "arg3" }]],
nvim args: 7
lua args: { "-arg1", "--arg2", "arg3" }]],
{},
{ '-arg1', '--arg2', 'arg3' }
)
@ -127,7 +129,8 @@ describe('startup', function()
-- nvim -l foo.lua --
assert_l_out([[
bufs:
args: {}]],
nvim args: 5
lua args: { "--" }]],
{},
{ '--' }
)
@ -135,8 +138,9 @@ describe('startup', function()
-- nvim file1 file2 -l foo.lua -arg1 -- file3 file4
assert_l_out([[
bufs: file1 file2 file3 file4
args: { "-arg1", "arg 2" }]],
bufs: file1 file2
nvim args: 11
lua args: { "-arg1", "arg 2", "--", "file3", "file4" }]],
{ 'file1', 'file2', },
{ '-arg1', 'arg 2', '--', 'file3', 'file4' }
)
@ -145,7 +149,8 @@ describe('startup', function()
-- nvim file1 file2 -l foo.lua -arg1 --
assert_l_out([[
bufs: file1 file2
args: { "-arg1" }]],
nvim args: 8
lua args: { "-arg1", "--" }]],
{ 'file1', 'file2', },
{ '-arg1', '--' }
)
@ -154,7 +159,8 @@ describe('startup', function()
-- nvim -l foo.lua <vim args>
assert_l_out([[
bufs:
args: { "-c", "set wrap?" }]],
nvim args: 6
lua args: { "-c", "set wrap?" }]],
{},
{ '-c', 'set wrap?' }
)
@ -167,7 +173,8 @@ describe('startup', function()
wrap
bufs:
args: { "-c", "set wrap?" }]],
nvim args: 8
lua args: { "-c", "set wrap?" }]],
{ '-c', 'set wrap?' },
{ '-c', 'set wrap?' }
)

View File

@ -23,7 +23,8 @@ end
local function main()
printbufs()
print('args:', vim.inspect(_G.arg))
print('nvim args:', #vim.v.argv)
print('lua args:', vim.inspect(_G.arg))
local exitcode = parseargs(_G.arg)
if type(exitcode) == 'number' then