mirror of
https://github.com/neovim/neovim.git
synced 2024-09-17 20:58:20 -04:00
feat(lua)!: execute Lua with "nvim -l"
Problem: Nvim has Lua but the "nvim" CLI can't easily be used to execute Lua scripts, especially scripts that take arguments or produce output. Solution: - support "nvim -l [args...]" for running scripts. closes #15749 - exit without +q - remove lua2dox_filter - remove Doxyfile. This wasn't used anyway, because the doxygen config is inlined in gen_vimdoc.py (`Doxyfile` variable). - use "nvim -l" in docs-gen CI job Examples: $ nvim -l scripts/lua2dox.lua --help Lua2DoX (0.2 20130128) ... $ echo "print(vim.inspect(_G.arg))" | nvim -l - --arg1 --arg2 $ echo 'print(vim.inspect(vim.api.nvim_buf_get_text(1,0,0,-1,-1,{})))' | nvim +"put ='text'" -l - TODO? -e executes Lua code -l loads a module -i enters REPL _after running the other arguments_.
This commit is contained in:
parent
39d70fcafd
commit
7c94bcd2d7
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -205,6 +205,8 @@ jobs:
|
||||
env:
|
||||
CC: ${{ matrix.cc }}
|
||||
CI_OS_NAME: ${{ matrix.os }}
|
||||
# TEST_FILE: test/functional/core/startup_spec.lua
|
||||
# TEST_FILTER: foo
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@ -281,6 +283,8 @@ jobs:
|
||||
DEPS_BUILD_DIR: ${{ github.workspace }}/nvim-deps
|
||||
CACHE_NVIM_DEPS_DIR: ${{ github.workspace }}/nvim-deps
|
||||
DEPS_PREFIX: ${{ github.workspace }}/nvim-deps/usr
|
||||
# TEST_FILE: test/functional/core/startup_spec.lua
|
||||
# TEST_FILTER: foo
|
||||
name: windows (MSVC_64)
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
@ -116,10 +116,7 @@ Each pull request must pass the automated builds on [Cirrus CI] and [GitHub Acti
|
||||
|
||||
- CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings
|
||||
will fail the build.
|
||||
- If any tests fail, the build will fail.
|
||||
See [test/README.md#running-tests][run-tests] to run tests locally.
|
||||
Passing locally doesn't guarantee passing the CI build, because of the
|
||||
different compilers and platforms tested against.
|
||||
- If any tests fail, the build will fail. See [test/README.md#running-tests][run-tests] to run tests locally.
|
||||
- CI runs [ASan] and other analyzers.
|
||||
- To run valgrind locally: `VALGRIND=1 make test`
|
||||
- To run Clang ASan/UBSan locally: `CC=clang make CMAKE_FLAGS="-DCLANG_ASAN_UBSAN=ON"`
|
||||
@ -127,6 +124,8 @@ Each pull request must pass the automated builds on [Cirrus CI] and [GitHub Acti
|
||||
neighbors_, to encourage incrementally updating the legacy style to meet our
|
||||
[style](#style). (See [#3174][3174] for background.)
|
||||
- CI for FreeBSD runs on [Cirrus CI].
|
||||
- To see CI results faster in your PR, you can temporarily set `TEST_FILE` in
|
||||
[ci.yml](https://github.com/neovim/neovim/blob/e35b9020b16985eee26e942f9a3f6b045bc3809b/.github/workflows/ci.yml#L205).
|
||||
|
||||
### Clang scan-build
|
||||
|
||||
|
@ -21,15 +21,19 @@ Nvim includes a "standard library" |lua-stdlib| for Lua. It complements the
|
||||
which can be used from Lua code (|lua-vimscript| |vim.api|). Together these
|
||||
"namespaces" form the Nvim programming interface.
|
||||
|
||||
See the |lua-guide| for an introduction to using Lua in Neovim.
|
||||
Lua plugins and user config are automatically discovered and loaded, just like
|
||||
Vimscript. See |lua-guide| for practical guidance.
|
||||
|
||||
You can also run Lua scripts from your shell using the |-l| argument: >
|
||||
nvim -l foo.lua [args...]
|
||||
<
|
||||
*lua-compat*
|
||||
Lua 5.1 is the permanent interface for Nvim Lua. Plugins need only consider
|
||||
Lua 5.1, not worry about forward-compatibility with future Lua versions. If
|
||||
Nvim ever ships with Lua 5.4+, a Lua 5.1 compatibility shim will be provided
|
||||
so that old plugins continue to work transparently.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
==============================================================================
|
||||
LUA CONCEPTS AND IDIOMS *lua-concepts*
|
||||
|
||||
Lua is very simple: this means that, while there are some quirks, once you
|
||||
@ -73,25 +77,24 @@ In Lua, any missing arguments are passed as `nil`. Example: >lua
|
||||
Furthermore it is not an error if extra parameters are passed, they are just
|
||||
discarded.
|
||||
|
||||
It is also allowed to omit the parentheses (only) if the function takes
|
||||
exactly one string (`"foo"`) or table literal (`{1,2,3}`). The latter is often
|
||||
used to approximate the "named parameters" feature of languages like Python
|
||||
("kwargs" or "keyword args"). Example: >lua
|
||||
*kwargs*
|
||||
When calling a function, you can omit the parentheses if the function takes
|
||||
exactly one string literal (`"foo"`) or table literal (`{1,2,3}`). The latter
|
||||
is often used to approximate "named parameters" ("kwargs" or "keyword args")
|
||||
as in languages like Python and C#. Example: >lua
|
||||
local func_with_opts = function(opts)
|
||||
local will_do_foo = opts.foo
|
||||
local filename = opts.filename
|
||||
|
||||
...
|
||||
end
|
||||
|
||||
func_with_opts { foo = true, filename = "hello.world" }
|
||||
<
|
||||
There is nothing special going on here except that parentheses are treated as
|
||||
There's nothing special going on here except that parentheses are treated as
|
||||
whitespace. But visually, this small bit of sugar gets reasonably close to
|
||||
a "keyword args" interface.
|
||||
|
||||
It is of course also valid to call the function with parentheses: >lua
|
||||
|
||||
func_with_opts({ foo = true, filename = "hello.world" })
|
||||
<
|
||||
Nvim tends to prefer the keyword args style.
|
||||
@ -100,25 +103,20 @@ Nvim tends to prefer the keyword args style.
|
||||
LUA PATTERNS *lua-patterns*
|
||||
|
||||
Lua intentionally does not support regular expressions, instead it has limited
|
||||
"patterns" which avoid the performance pitfalls of extended regex.
|
||||
|luaref-patterns|
|
||||
"patterns" |luaref-patterns| which avoid the performance pitfalls of extended
|
||||
regex. Lua scripts can also use Vim regex via |vim.regex()|.
|
||||
|
||||
Examples using |string.match()|: >lua
|
||||
These examples use |string.match()| to demonstrate Lua patterns: >lua
|
||||
|
||||
print(string.match("foo123bar123", "%d+"))
|
||||
-- 123
|
||||
|
||||
print(string.match("foo123bar123", "[^%d]+"))
|
||||
-- foo
|
||||
|
||||
print(string.match("foo123bar123", "[abc]+"))
|
||||
-- ba
|
||||
|
||||
print(string.match("foo.bar", "%.bar"))
|
||||
-- .bar
|
||||
|
||||
For more complex matching you can use Vim regex from Lua via |vim.regex()|.
|
||||
|
||||
==============================================================================
|
||||
IMPORTING LUA MODULES *require()* *lua-require*
|
||||
|
||||
@ -389,7 +387,7 @@ For example consider the following Lua omnifunc handler: >lua
|
||||
vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omnifunc')
|
||||
|
||||
Note: The module ("mymod" in the above example) must either be a Lua global,
|
||||
or use the require syntax as specified above to access it from a package.
|
||||
or use require() as shown above to access it from a package.
|
||||
|
||||
Note: `v:lua` without a call is not allowed in a Vimscript expression:
|
||||
|Funcref|s cannot represent Lua functions. The following are errors: >vim
|
||||
|
@ -57,6 +57,11 @@ The following new APIs or features were added.
|
||||
<
|
||||
(or the Vimscript equivalent) to their |config| file.
|
||||
|
||||
• Run Lua scripts from your shell using |-l|. >
|
||||
nvim -l foo.lua --arg1 --arg2
|
||||
< Also works with stdin: >
|
||||
echo "print(42)" | nvim -l -
|
||||
|
||||
• Added a |vim.lsp.codelens.clear()| function to clear codelenses.
|
||||
|
||||
• |vim.inspect_pos()|, |vim.show_pos()| and |:Inspect| allow a user to get or show items
|
||||
|
@ -9,7 +9,7 @@ Starting Vim *starting*
|
||||
Type |gO| to see the table of contents.
|
||||
|
||||
==============================================================================
|
||||
Nvim arguments *vim-arguments*
|
||||
Nvim arguments *cli-arguments*
|
||||
|
||||
Most often, Nvim is started to edit a single file with the command: >
|
||||
|
||||
@ -31,8 +31,8 @@ filename One or more file names. The first one will be the current
|
||||
To avoid a file name starting with a '-' being interpreted as
|
||||
an option, precede the arglist with "--", e.g.: >
|
||||
nvim -- -filename
|
||||
< All arguments after the "--" will be interpreted as file names,
|
||||
no other options or "+command" argument can follow.
|
||||
< All arguments after "--" are interpreted as file names, no
|
||||
other options or "+command" argument can follow.
|
||||
|
||||
*--*
|
||||
`-` Alias for stdin (standard input).
|
||||
@ -143,15 +143,13 @@ 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. Equivalent to: >
|
||||
-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: >
|
||||
-c "source {file}"
|
||||
< Can be repeated like "-c", subject to the same limit of 10
|
||||
"-c" arguments. {file} cannot start with a "-".
|
||||
|
||||
-S Works like "-S Session.vim". Only when used as the last
|
||||
argument or when another "-" option follows.
|
||||
|
||||
-L *-L* *-r*
|
||||
-r Recovery mode. Without a file name argument, a list of
|
||||
existing swap files is given. With a file name, a swap file
|
||||
@ -211,10 +209,30 @@ argument.
|
||||
nvim -es +":verbose echo 'foo'"
|
||||
nvim -V1 -es +foo
|
||||
|
||||
< User |config| is skipped (unless given with |-u|).
|
||||
< User |config| is skipped unless |-u| was given.
|
||||
Swap file is skipped (like |-n|).
|
||||
User |shada| is loaded (unless "-i NONE" is given).
|
||||
|
||||
*-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.
|
||||
|
||||
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": >
|
||||
nvim +q -l foo.lua
|
||||
< 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|).
|
||||
|
||||
*-b*
|
||||
-b Binary mode. File I/O will only recognize <NL> to separate
|
||||
lines. The 'expandtab' option will be reset. The 'textwidth'
|
||||
@ -222,9 +240,6 @@ argument.
|
||||
is set. This is done after reading the |vimrc| but before
|
||||
reading any file in the arglist. See also |edit-binary|.
|
||||
|
||||
*-l*
|
||||
-l Lisp mode. Sets the 'lisp' and 'showmatch' options on.
|
||||
|
||||
*-A*
|
||||
-A Arabic mode. Sets the 'arabic' option on.
|
||||
|
||||
@ -239,10 +254,10 @@ argument.
|
||||
Example: >
|
||||
nvim -V8
|
||||
|
||||
-V[N]{filename}
|
||||
Like -V and set 'verbosefile' to {filename}. Messages are not
|
||||
displayed; instead they are written to the file {filename}.
|
||||
{filename} must not start with a digit.
|
||||
-V[N]{file}
|
||||
Like -V and sets 'verbosefile' to {file} (must not start with
|
||||
a digit). Messages are not displayed; instead they are
|
||||
written to {file}.
|
||||
Example: >
|
||||
nvim -V20vimlog
|
||||
<
|
||||
|
@ -55,11 +55,19 @@ if sys.version_info < MIN_PYTHON_VERSION:
|
||||
doxygen_version = tuple((int(i) for i in subprocess.check_output(["doxygen", "-v"],
|
||||
universal_newlines=True).split()[0].split('.')))
|
||||
|
||||
# Until 0.9 is released, need this hacky way to check that "nvim -l foo.lua" works.
|
||||
nvim_version = list(line for line in subprocess.check_output(['nvim', '-h'], universal_newlines=True).split('\n')
|
||||
if '-l ' in line)
|
||||
|
||||
if doxygen_version < MIN_DOXYGEN_VERSION:
|
||||
print("\nRequires doxygen {}.{}.{}+".format(*MIN_DOXYGEN_VERSION))
|
||||
print("Your doxygen version is {}.{}.{}\n".format(*doxygen_version))
|
||||
sys.exit(1)
|
||||
|
||||
if len(nvim_version) == 0:
|
||||
print("\nRequires 'nvim -l' feature, see https://github.com/neovim/neovim/pull/18706")
|
||||
sys.exit(1)
|
||||
|
||||
# DEBUG = ('DEBUG' in os.environ)
|
||||
INCLUDE_C_DECL = ('INCLUDE_C_DECL' in os.environ)
|
||||
INCLUDE_DEPRECATED = ('INCLUDE_DEPRECATED' in os.environ)
|
||||
@ -79,7 +87,7 @@ base_dir = os.path.dirname(os.path.dirname(script_path))
|
||||
out_dir = os.path.join(base_dir, 'tmp-{target}-doc')
|
||||
filter_cmd = '%s %s' % (sys.executable, script_path)
|
||||
msgs = [] # Messages to show on exit.
|
||||
lua2dox_filter = os.path.join(base_dir, 'scripts', 'lua2dox_filter')
|
||||
lua2dox = os.path.join(base_dir, 'scripts', 'lua2dox.lua')
|
||||
|
||||
CONFIG = {
|
||||
'api': {
|
||||
@ -993,7 +1001,7 @@ def delete_lines_below(filename, tokenstr):
|
||||
fp.writelines(lines[0:i])
|
||||
|
||||
|
||||
def main(config, args):
|
||||
def main(doxygen_config, args):
|
||||
"""Generates:
|
||||
|
||||
1. Vim :help docs
|
||||
@ -1021,7 +1029,7 @@ def main(config, args):
|
||||
# runtime/lua/vim/lsp.lua:209: warning: argument 'foo' not found
|
||||
stderr=(subprocess.STDOUT if debug else subprocess.DEVNULL))
|
||||
p.communicate(
|
||||
config.format(
|
||||
doxygen_config.format(
|
||||
input=' '.join(
|
||||
[f'"{file}"' for file in CONFIG[target]['files']]),
|
||||
output=output_dir,
|
||||
@ -1108,11 +1116,7 @@ def main(config, args):
|
||||
fn_map_full.update(fn_map)
|
||||
|
||||
if len(sections) == 0:
|
||||
if target == 'lua':
|
||||
fail(f'no sections for target: {target} (this usually means'
|
||||
+ ' "luajit" was not found by scripts/lua2dox_filter)')
|
||||
else:
|
||||
fail(f'no sections for target: {target}')
|
||||
fail(f'no sections for target: {target} (look for errors near "Preprocessing" log lines above)')
|
||||
if len(sections) > len(CONFIG[target]['section_order']):
|
||||
raise RuntimeError(
|
||||
'found new modules "{}"; update the "section_order" map'.format(
|
||||
@ -1159,7 +1163,7 @@ def main(config, args):
|
||||
def filter_source(filename):
|
||||
name, extension = os.path.splitext(filename)
|
||||
if extension == '.lua':
|
||||
p = subprocess.run([lua2dox_filter, filename], stdout=subprocess.PIPE)
|
||||
p = subprocess.run(['nvim', '-l', lua2dox, filename], stdout=subprocess.PIPE)
|
||||
op = ('?' if 0 != p.returncode else p.stdout.decode('utf-8'))
|
||||
print(op)
|
||||
else:
|
||||
|
@ -27,14 +27,13 @@ http://search.cpan.org/~alec/Doxygen-Lua-0.02/lib/Doxygen/Lua.pm
|
||||
Running
|
||||
-------
|
||||
|
||||
This file "lua2dox.lua" gets called by "lua2dox_filter" (bash).
|
||||
This script "lua2dox.lua" gets called by "gen_vimdoc.py".
|
||||
|
||||
Doxygen must be on your system. You can experiment like so:
|
||||
|
||||
- Run "doxygen -g" to create a default Doxyfile.
|
||||
- Then alter it to let it recognise lua. Add the two following lines:
|
||||
- Then alter it to let it recognise lua. Add the following line:
|
||||
FILE_PATTERNS = *.lua
|
||||
FILTER_PATTERNS = *.lua=lua2dox_filter
|
||||
- Then run "doxygen".
|
||||
|
||||
The core function reads the input file (filename or stdin) and outputs some pseudo C-ish language.
|
||||
@ -117,26 +116,6 @@ local function string_split(Str, Pattern)
|
||||
return splitStr
|
||||
end
|
||||
|
||||
--! \class TCore_Commandline
|
||||
--! \brief reads/parses commandline
|
||||
local TCore_Commandline = class()
|
||||
|
||||
--! \brief constructor
|
||||
function TCore_Commandline.init(this)
|
||||
this.argv = arg
|
||||
this.parsed = {}
|
||||
this.params = {}
|
||||
end
|
||||
|
||||
--! \brief get value
|
||||
function TCore_Commandline.getRaw(this, Key, Default)
|
||||
local val = this.argv[Key]
|
||||
if not val then
|
||||
val = Default
|
||||
end
|
||||
return val
|
||||
end
|
||||
|
||||
-------------------------------
|
||||
--! \brief file buffer
|
||||
--!
|
||||
@ -147,7 +126,7 @@ local TStream_Read = class()
|
||||
--!
|
||||
--! \param Filename name of file to read (or nil == stdin)
|
||||
function TStream_Read.getContents(this, Filename)
|
||||
assert(Filename)
|
||||
assert(Filename, ('invalid file: %s'):format(Filename))
|
||||
-- get lines from file
|
||||
-- syphon lines to our table
|
||||
local filecontents = {}
|
||||
@ -548,15 +527,14 @@ end
|
||||
local This_app = TApp()
|
||||
|
||||
--main
|
||||
local cl = TCore_Commandline()
|
||||
|
||||
local argv1 = cl:getRaw(2)
|
||||
local argv1 = arg[1]
|
||||
if argv1 == '--help' then
|
||||
TCore_IO_writeln(This_app:getVersion())
|
||||
TCore_IO_writeln(This_app:getCopyright())
|
||||
TCore_IO_writeln([[
|
||||
run as:
|
||||
lua2dox_filter <param>
|
||||
nvim -l scripts/lua2dox.lua <param>
|
||||
--------------
|
||||
Param:
|
||||
<filename> : interprets filename
|
||||
|
@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
###########################################################################
|
||||
# Copyright (C) 2012 by Simon Dales #
|
||||
# simon@purrsoft.co.uk #
|
||||
# #
|
||||
# This program is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program; if not, write to the #
|
||||
# Free Software Foundation, Inc., #
|
||||
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
|
||||
###########################################################################
|
||||
LANG=""
|
||||
|
||||
##! \brief test executable to see if it exists
|
||||
test_executable() {
|
||||
P_EXE="$1"
|
||||
#########
|
||||
WHICH=$(which "$P_EXE")
|
||||
if test -z "${WHICH}"; then
|
||||
echo "not found \"${P_EXE}\""
|
||||
else
|
||||
EXE="${P_EXE}"
|
||||
fi
|
||||
}
|
||||
|
||||
##! \brief sets the lua interpreter
|
||||
set_lua() {
|
||||
if test -z "${EXE}"; then
|
||||
test_executable '.deps/usr/bin/luajit'
|
||||
fi
|
||||
|
||||
if test -z "${EXE}"; then
|
||||
test_executable 'luajit'
|
||||
fi
|
||||
|
||||
if test -z "${EXE}"; then
|
||||
test_executable 'lua'
|
||||
fi
|
||||
}
|
||||
|
||||
##! \brief makes canonical name of file
|
||||
##!
|
||||
##! Note that "readlink -f" doesn't work in MacOSX
|
||||
##!
|
||||
do_readlink() {
|
||||
pushd . > /dev/null
|
||||
TARGET_FILE=$1
|
||||
|
||||
cd "$(dirname $TARGET_FILE)"
|
||||
TARGET_FILE=$(basename "$TARGET_FILE")
|
||||
|
||||
# Iterate down a (possible) chain of symlinks
|
||||
while [ -L "$TARGET_FILE" ]; do
|
||||
TARGET_FILE=$(readlink "$TARGET_FILE")
|
||||
cd $(dirname "$TARGET_FILE")
|
||||
TARGET_FILE=$(basename "$TARGET_FILE")
|
||||
done
|
||||
|
||||
PHYS_DIR=$(pwd -P)
|
||||
RESULT=$PHYS_DIR
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
##main
|
||||
set_lua
|
||||
if test -z "${EXE}"; then
|
||||
echo "no lua interpreter found"
|
||||
exit 1
|
||||
else
|
||||
BASENAME=$(basename "$0")
|
||||
do_readlink "$0"
|
||||
DIRNAME="${RESULT}"
|
||||
|
||||
LUASCRIPT="${DIRNAME}/lua2dox.lua ${BASENAME}"
|
||||
#echo "lua[${LUASCRIPT}]"
|
||||
|
||||
${EXE} ${LUASCRIPT} $@
|
||||
fi
|
||||
|
||||
##eof
|
2566
src/Doxyfile
2566
src/Doxyfile
File diff suppressed because it is too large
Load Diff
@ -515,7 +515,7 @@ EXTERN int allbuf_lock INIT(= 0);
|
||||
/// not allowed then.
|
||||
EXTERN int sandbox INIT(= 0);
|
||||
|
||||
/// Batch-mode: "-es" or "-Es" commandline argument was given.
|
||||
/// Batch-mode: "-es", "-Es", "-l" commandline argument was given.
|
||||
EXTERN int silent_mode INIT(= false);
|
||||
|
||||
/// Start position of active Visual selection.
|
||||
|
@ -323,6 +323,34 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Copies all args into the Lua `arg` global.
|
||||
///
|
||||
/// Example:
|
||||
/// nvim -l foo.lua -- -e "sin=math.sin" script a b
|
||||
///
|
||||
/// @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)
|
||||
{
|
||||
lua_State *const L = global_lstate;
|
||||
lua_newtable(L);
|
||||
int i = 0;
|
||||
for (; i < argc; i++) {
|
||||
if (strequal("--", argv[i])) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
lua_pushstring(L, argv[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
lua_setglobal(L, "arg");
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static void nlua_schedule_event(void **argv)
|
||||
{
|
||||
LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
|
||||
|
@ -275,14 +275,14 @@ int main(int argc, char **argv)
|
||||
// Check if we have an interactive window.
|
||||
check_and_set_isatty(¶ms);
|
||||
|
||||
// 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(¶ms);
|
||||
|
||||
nlua_init();
|
||||
|
||||
TIME_MSG("init lua interpreter");
|
||||
|
||||
if (embedded_mode) {
|
||||
const char *err;
|
||||
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
|
||||
@ -363,8 +363,7 @@ int main(int argc, char **argv)
|
||||
debug_break_level = params.use_debug_break_level;
|
||||
|
||||
// Read ex-commands if invoked with "-es".
|
||||
if (!params.input_isatty && !params.input_neverscript
|
||||
&& silent_mode && exmode_active) {
|
||||
if (!params.input_isatty && !params.input_istext && silent_mode && exmode_active) {
|
||||
input_start(STDIN_FILENO);
|
||||
}
|
||||
|
||||
@ -409,14 +408,12 @@ int main(int argc, char **argv)
|
||||
init_default_autocmds();
|
||||
TIME_MSG("init default autocommands");
|
||||
|
||||
bool vimrc_none = params.use_vimrc != NULL && strequal(params.use_vimrc, "NONE");
|
||||
bool vimrc_none = strequal(params.use_vimrc, "NONE");
|
||||
|
||||
// Reset 'loadplugins' for "-u NONE" before "--cmd" arguments.
|
||||
// Allows for setting 'loadplugins' there.
|
||||
if (vimrc_none) {
|
||||
// When using --clean we still want to load plugins
|
||||
p_lpl = params.clean;
|
||||
}
|
||||
// For --clean we still want to load plugins.
|
||||
p_lpl = vimrc_none ? params.clean : p_lpl;
|
||||
|
||||
// Execute --cmd arguments.
|
||||
exe_pre_commands(¶ms);
|
||||
@ -610,6 +607,11 @@ int main(int argc, char **argv)
|
||||
(void)eval_has_provider("clipboard");
|
||||
}
|
||||
|
||||
if (params.luaf != NULL) {
|
||||
nlua_exec_file(params.luaf);
|
||||
// return 0;
|
||||
}
|
||||
|
||||
TIME_MSG("before starting main loop");
|
||||
ILOG("starting main loop");
|
||||
|
||||
@ -962,7 +964,7 @@ static bool edit_stdin(mparm_T *parmp)
|
||||
{
|
||||
bool implicit = !headless_mode
|
||||
&& !(embedded_mode && stdin_fd <= 0)
|
||||
&& (!exmode_active || parmp->input_neverscript)
|
||||
&& (!exmode_active || parmp->input_istext)
|
||||
&& !parmp->input_isatty
|
||||
&& parmp->scriptin == NULL; // `-s -` was not given.
|
||||
return parmp->had_stdin_file || implicit;
|
||||
@ -993,9 +995,9 @@ static void command_line_scan(mparm_T *parmp)
|
||||
} else {
|
||||
parmp->commands[parmp->n_commands++] = &(argv[0][1]);
|
||||
}
|
||||
|
||||
// Optional argument.
|
||||
} else if (argv[0][0] == '-' && !had_minmin) {
|
||||
// Optional argument.
|
||||
|
||||
want_argument = false;
|
||||
char c = argv[0][argv_idx++];
|
||||
switch (c) {
|
||||
@ -1005,9 +1007,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
silent_mode = true;
|
||||
parmp->no_swap_file = true;
|
||||
} else {
|
||||
if (parmp->edit_type != EDIT_NONE
|
||||
&& parmp->edit_type != EDIT_FILE
|
||||
&& parmp->edit_type != EDIT_STDIN) {
|
||||
if (parmp->edit_type > EDIT_STDIN) {
|
||||
mainerr(err_too_many_args, argv[0]);
|
||||
}
|
||||
parmp->had_stdin_file = true;
|
||||
@ -1015,7 +1015,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
}
|
||||
argv_idx = -1; // skip to next argument
|
||||
break;
|
||||
case '-': // "--" don't take any more option arguments
|
||||
case '-': // "--" No more option arguments.
|
||||
// "--help" give help message
|
||||
// "--version" give version message
|
||||
// "--noplugin[s]" skip plugins
|
||||
@ -1111,7 +1111,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
break;
|
||||
case 'E': // "-E" Ex mode
|
||||
exmode_active = true;
|
||||
parmp->input_neverscript = true;
|
||||
parmp->input_istext = true;
|
||||
break;
|
||||
case 'f': // "-f" GUI: run in foreground.
|
||||
break;
|
||||
@ -1123,10 +1123,6 @@ static void command_line_scan(mparm_T *parmp)
|
||||
p_hkmap = true;
|
||||
set_option_value_give_err("rl", 1L, NULL, 0);
|
||||
break;
|
||||
case 'l': // "-l" lisp mode, 'lisp' and 'showmatch' on.
|
||||
set_option_value_give_err("lisp", 1L, NULL, 0);
|
||||
p_sm = true;
|
||||
break;
|
||||
case 'M': // "-M" no changes or writing of files
|
||||
reset_modifiable();
|
||||
FALLTHROUGH;
|
||||
@ -1231,6 +1227,7 @@ static void command_line_scan(mparm_T *parmp)
|
||||
FALLTHROUGH;
|
||||
case 'S': // "-S {file}" execute Vim script
|
||||
case 'i': // "-i {shada}" use for ShaDa file
|
||||
case 'l': // "-l {file}" Lua mode
|
||||
case 'u': // "-u {vimrc}" vim inits file
|
||||
case 'U': // "-U {gvimrc}" gvim inits file
|
||||
case 'W': // "-W {scriptout}" overwrite
|
||||
@ -1311,6 +1308,27 @@ static void command_line_scan(mparm_T *parmp)
|
||||
set_option_value_give_err("shadafile", 0L, argv[0], 0);
|
||||
break;
|
||||
|
||||
case 'l': // "-l" Lua script: args after "-l".
|
||||
silent_mode = true;
|
||||
p_verbose = 1;
|
||||
parmp->no_swap_file = true;
|
||||
parmp->use_vimrc = parmp->use_vimrc ? parmp->use_vimrc : "NONE";
|
||||
if (p_shadafile == NULL || *p_shadafile == NUL) {
|
||||
set_option_value_give_err("shadafile", 0L, "NONE", 0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's': // "-s {scriptin}" read from script file
|
||||
if (parmp->scriptin != NULL) {
|
||||
scripterror:
|
||||
@ -1354,9 +1372,7 @@ scripterror:
|
||||
argv_idx = -1; // skip to next argument
|
||||
|
||||
// Check for only one type of editing.
|
||||
if (parmp->edit_type != EDIT_NONE
|
||||
&& parmp->edit_type != EDIT_FILE
|
||||
&& parmp->edit_type != EDIT_STDIN) {
|
||||
if (parmp->edit_type > EDIT_STDIN) {
|
||||
mainerr(err_too_many_args, argv[0]);
|
||||
}
|
||||
parmp->edit_type = EDIT_FILE;
|
||||
@ -1421,6 +1437,7 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
|
||||
paramp->listen_addr = NULL;
|
||||
paramp->server_addr = NULL;
|
||||
paramp->remote = 0;
|
||||
paramp->luaf = NULL;
|
||||
}
|
||||
|
||||
/// Initialize global startuptime file if "--startuptime" passed as an argument.
|
||||
@ -2154,6 +2171,7 @@ static void usage(void)
|
||||
os_msg(_(" + Start at end of file\n"));
|
||||
os_msg(_(" --cmd <cmd> Execute <cmd> before any config\n"));
|
||||
os_msg(_(" +<cmd>, -c <cmd> Execute <cmd> after config and first file\n"));
|
||||
os_msg(_(" -l <script> [args...] Execute Lua <script> (with optional args)\n"));
|
||||
os_msg("\n");
|
||||
os_msg(_(" -b Binary mode\n"));
|
||||
os_msg(_(" -d Diff mode\n"));
|
||||
|
@ -23,15 +23,17 @@ typedef struct {
|
||||
char cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
|
||||
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 edit_type; // type of editing to do
|
||||
char *tagname; // tag from -t argument
|
||||
char *use_ef; // 'errorfile' from -q argument
|
||||
|
||||
bool input_isatty; // stdin is a terminal
|
||||
bool input_istext; // stdin is text, not executable (-E/-Es)
|
||||
bool output_isatty; // stdout is a terminal
|
||||
bool err_isatty; // stderr is a terminal
|
||||
bool input_neverscript; // never treat stdin as script (-E/-Es)
|
||||
|
||||
int no_swap_file; // "-n" argument used
|
||||
int use_debug_break_level;
|
||||
int window_count; // number of windows to use
|
||||
|
@ -962,6 +962,7 @@ endfunc
|
||||
|
||||
" Test for enabling the lisp mode on startup
|
||||
func Test_l_arg()
|
||||
throw 'Skipped: Nvim -l arg differs from Vim'
|
||||
let after =<< trim [CODE]
|
||||
let s = 'lisp=' .. &lisp .. ', showmatch=' .. &showmatch
|
||||
call writefile([s], 'Xtestout')
|
||||
|
@ -26,6 +26,7 @@ local write_file = helpers.write_file
|
||||
local meths = helpers.meths
|
||||
local alter_slashes = helpers.alter_slashes
|
||||
local is_os = helpers.is_os
|
||||
local dedent = helpers.dedent
|
||||
|
||||
local testfile = 'Xtest_startuptime'
|
||||
after_each(function()
|
||||
@ -47,6 +48,34 @@ describe('startup', function()
|
||||
assert_log("require%('vim%._editor'%)", testfile, 100)
|
||||
end)
|
||||
end)
|
||||
|
||||
it('-D does not hang #12647', function()
|
||||
clear()
|
||||
local screen
|
||||
screen = Screen.new(60, 7)
|
||||
screen:attach()
|
||||
command([[let g:id = termopen('"]]..nvim_prog..
|
||||
[[" -u NONE -i NONE --cmd "set noruler" -D')]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
|
|
||||
Entering Debug mode. Type "cont" to continue. |
|
||||
nvim_exec() |
|
||||
cmd: aunmenu * |
|
||||
> |
|
||||
|
|
||||
]])
|
||||
command([[call chansend(g:id, "cont\n")]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
[No Name] |
|
||||
|
|
||||
|
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('startup', function()
|
||||
@ -58,6 +87,94 @@ describe('startup', function()
|
||||
os.remove('Xtest_startup_ttyout')
|
||||
end)
|
||||
|
||||
describe('-l Lua', function()
|
||||
local function assert_l_out(expected, args_before, args_after)
|
||||
local args = { nvim_prog, '--clean' }
|
||||
vim.list_extend(args, args_before or {})
|
||||
vim.list_extend(args, { '-l', 'test/functional/fixtures/startup.lua' })
|
||||
vim.list_extend(args, args_after or {})
|
||||
local out = funcs.system(args):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' }))
|
||||
eq(1, eval('v:shell_error'))
|
||||
end)
|
||||
|
||||
it('os.exit() sets Nvim exitcode', function()
|
||||
-- nvim -l foo.lua -arg1 -- a b c
|
||||
assert_l_out([[
|
||||
bufs:
|
||||
args: { "-arg1", "--exitcode", "73", "--arg2" }]],
|
||||
{},
|
||||
{ '-arg1', "--exitcode", "73", '--arg2' }
|
||||
)
|
||||
eq(73, eval('v:shell_error'))
|
||||
end)
|
||||
|
||||
it('sets _G.arg', function()
|
||||
-- nvim -l foo.lua -arg1 -- a b c
|
||||
assert_l_out([[
|
||||
bufs:
|
||||
args: { "-arg1", "--arg2", "arg3" }]],
|
||||
{},
|
||||
{ '-arg1', '--arg2', 'arg3' }
|
||||
)
|
||||
eq(0, eval('v:shell_error'))
|
||||
|
||||
-- nvim -l foo.lua --
|
||||
assert_l_out([[
|
||||
bufs:
|
||||
args: {}]],
|
||||
{},
|
||||
{ '--' }
|
||||
)
|
||||
eq(0, eval('v:shell_error'))
|
||||
|
||||
-- nvim file1 file2 -l foo.lua -arg1 -- file3 file4
|
||||
assert_l_out([[
|
||||
bufs: file1 file2 file3 file4
|
||||
args: { "-arg1", "arg 2" }]],
|
||||
{ 'file1', 'file2', },
|
||||
{ '-arg1', 'arg 2', '--', 'file3', 'file4' }
|
||||
)
|
||||
eq(0, eval('v:shell_error'))
|
||||
|
||||
-- nvim file1 file2 -l foo.lua -arg1 --
|
||||
assert_l_out([[
|
||||
bufs: file1 file2
|
||||
args: { "-arg1" }]],
|
||||
{ 'file1', 'file2', },
|
||||
{ '-arg1', '--' }
|
||||
)
|
||||
eq(0, eval('v:shell_error'))
|
||||
|
||||
-- nvim -l foo.lua <vim args>
|
||||
assert_l_out([[
|
||||
bufs:
|
||||
args: { "-c", "set wrap?" }]],
|
||||
{},
|
||||
{ '-c', 'set wrap?' }
|
||||
)
|
||||
eq(0, eval('v:shell_error'))
|
||||
|
||||
-- nvim <vim args> -l foo.lua <vim args>
|
||||
assert_l_out(
|
||||
-- luacheck: ignore 611 (Line contains only whitespaces)
|
||||
[[
|
||||
wrap
|
||||
|
||||
bufs:
|
||||
args: { "-c", "set wrap?" }]],
|
||||
{ '-c', 'set wrap?' },
|
||||
{ '-c', 'set wrap?' }
|
||||
)
|
||||
eq(0, eval('v:shell_error'))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('pipe at both ends: has("ttyin")==0 has("ttyout")==0', function()
|
||||
-- system() puts a pipe at both ends.
|
||||
local out = funcs.system({ nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless',
|
||||
@ -66,6 +183,7 @@ describe('startup', function()
|
||||
'+q' })
|
||||
eq('0 0', out)
|
||||
end)
|
||||
|
||||
it('with --embed: has("ttyin")==0 has("ttyout")==0', function()
|
||||
local screen = Screen.new(25, 3)
|
||||
-- Remote UI connected by --embed.
|
||||
@ -77,6 +195,7 @@ describe('startup', function()
|
||||
0 0 |
|
||||
]])
|
||||
end)
|
||||
|
||||
it('in a TTY: has("ttyin")==1 has("ttyout")==1', function()
|
||||
local screen = Screen.new(25, 4)
|
||||
screen:attach()
|
||||
@ -95,6 +214,7 @@ describe('startup', function()
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('output to pipe: has("ttyin")==1 has("ttyout")==0', function()
|
||||
if is_os('win') then
|
||||
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
|
||||
@ -111,6 +231,7 @@ describe('startup', function()
|
||||
read_file('Xtest_startup_ttyout'))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('input from pipe: has("ttyin")==0 has("ttyout")==1', function()
|
||||
if is_os('win') then
|
||||
command([[set shellcmdflag=/s\ /c shellxquote=\"]])
|
||||
@ -128,6 +249,7 @@ describe('startup', function()
|
||||
read_file('Xtest_startup_ttyout'))
|
||||
end)
|
||||
end)
|
||||
|
||||
it('input from pipe (implicit) #7679', function()
|
||||
local screen = Screen.new(25, 4)
|
||||
screen:attach()
|
||||
@ -147,6 +269,7 @@ describe('startup', function()
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
it('input from pipe + file args #7679', function()
|
||||
eq('ohyeah\r\n0 0 bufs=3',
|
||||
funcs.system({nvim_prog, '-n', '-u', 'NONE', '-i', 'NONE', '--headless',
|
||||
@ -532,32 +655,6 @@ describe('sysinit', function()
|
||||
eval('printf("loaded %d xdg %d vim %d", g:loaded, get(g:, "xdg", 0), get(g:, "vim", 0))'))
|
||||
end)
|
||||
|
||||
it('fixed hang issue with -D (#12647)', function()
|
||||
local screen
|
||||
screen = Screen.new(60, 7)
|
||||
screen:attach()
|
||||
command([[let g:id = termopen('"]]..nvim_prog..
|
||||
[[" -u NONE -i NONE --cmd "set noruler" -D')]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
Entering Debug mode. Type "cont" to continue. |
|
||||
nvim_exec() |
|
||||
cmd: aunmenu * |
|
||||
> |
|
||||
<" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All|
|
||||
|
|
||||
]])
|
||||
command([[call chansend(g:id, "cont\n")]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
[No Name] |
|
||||
|
|
||||
<" -u NONE -i NONE --cmd "set noruler" -D 1,0-1 All|
|
||||
|
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('user config init', function()
|
||||
|
34
test/functional/fixtures/startup.lua
Normal file
34
test/functional/fixtures/startup.lua
Normal file
@ -0,0 +1,34 @@
|
||||
-- Test "nvim -l foo.lua …"
|
||||
|
||||
local function printbufs()
|
||||
local bufs = ''
|
||||
for _, v in ipairs(vim.api.nvim_list_bufs()) do
|
||||
local b = vim.fn.bufname(v)
|
||||
if b:len() > 0 then
|
||||
bufs = ('%s %s'):format(bufs, b)
|
||||
end
|
||||
end
|
||||
print(('bufs:%s'):format(bufs))
|
||||
end
|
||||
|
||||
local function parseargs(args)
|
||||
local exitcode = nil
|
||||
for i = 1, #args do
|
||||
if args[i] == '--exitcode' then
|
||||
exitcode = tonumber(args[i + 1])
|
||||
end
|
||||
end
|
||||
return exitcode
|
||||
end
|
||||
|
||||
local function main()
|
||||
printbufs()
|
||||
print('args:', vim.inspect(_G.arg))
|
||||
|
||||
local exitcode = parseargs(_G.arg)
|
||||
if type(exitcode) == 'number' then
|
||||
os.exit(exitcode)
|
||||
end
|
||||
end
|
||||
|
||||
main()
|
Loading…
Reference in New Issue
Block a user