docs(lua): update ":{range}lua" docs + error message #27231

- `:lua (no file)` is misleading because `:lua` never takes a file arg,
  unlike `:source`.
- Update various related docs.
This commit is contained in:
Justin M. Keyes
2024-01-27 10:40:30 -08:00
committed by GitHub
parent 17b298b7c8
commit 2cd76a758b
5 changed files with 49 additions and 32 deletions

View File

@@ -255,10 +255,13 @@ arguments separated by " " (space) instead of "\t" (tab).
:lua =jit.version :lua =jit.version
< <
:{range}lua :{range}lua
Executes the |[range]| in the current buffer as Lua code. Unlike |:source|, Executes buffer lines in {range} as Lua code. Unlike |:source|, this
this will execute the specified lines regardless of the extension or always treats the lines as Lua code.
|'filetype'| of the buffer.
Example: select the following code and type ":lua<Enter>" to execute it: >lua
print(string.format(
'unix time: %s', os.time()))
<
*:lua-heredoc* *:lua-heredoc*
:lua << [trim] [{endmarker}] :lua << [trim] [{endmarker}]
{script} {script}
@@ -271,10 +274,8 @@ arguments separated by " " (space) instead of "\t" (tab).
function! CurrentLineInfo() function! CurrentLineInfo()
lua << EOF lua << EOF
local linenr = vim.api.nvim_win_get_cursor(0)[1] local linenr = vim.api.nvim_win_get_cursor(0)[1]
local curline = vim.api.nvim_buf_get_lines( local curline = vim.api.nvim_buf_get_lines(0, linenr - 1, linenr, false)[1]
0, linenr - 1, linenr, false)[1] print(string.format('Line [%d] has %d bytes', linenr, #curline))
print(string.format("Current line [%d] has %d bytes",
linenr, #curline))
EOF EOF
endfunction endfunction
< <

View File

@@ -192,11 +192,11 @@ Using Vim scripts *using-scripts*
For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
*:so* *:source* *load-vim-script* *:so* *:source* *load-vim-script*
:[range]so[urce] [file] Runs |Ex| commands or Lua code (".lua" files) from :[range]so[urce] [file] Runs |Ex-commands| or Lua code (".lua" files) from
[file]. [file].
If no [file], the current buffer is used, and it is If no [file], the current buffer is used and treated
treated as Lua code if its 'filetype' is "lua" or its as Lua code if 'filetype' is "lua" or its filename
file name ends with ".lua". ends with ".lua".
Triggers the |SourcePre| autocommand. Triggers the |SourcePre| autocommand.
*:source!* *:source!*
:[range]so[urce]! {file} :[range]so[urce]! {file}

View File

@@ -1641,19 +1641,20 @@ bool nlua_is_deferred_safe(void)
return in_fast_callback == 0; return in_fast_callback == 0;
} }
/// Run lua string /// Executes Lua code.
/// ///
/// Used for :lua. /// Implements `:lua` and `:lua ={expr}`.
/// ///
/// @param eap Vimscript command being run. /// @param eap Vimscript `:lua {code}`, `:{range}lua`, or `:lua ={expr}` command.
void ex_lua(exarg_T *const eap) void ex_lua(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
// ":{range}lua"
if (eap->addr_count > 0 || *eap->arg == NUL) { if (eap->addr_count > 0 || *eap->arg == NUL) {
if (eap->addr_count > 0 && *eap->arg == NUL) { if (eap->addr_count > 0 && *eap->arg == NUL) {
cmd_source_buffer(eap, true); cmd_source_buffer(eap, true);
} else { } else {
semsg(_(e_invarg2), "exactly one of {chunk} and {range} required"); semsg(_(e_invarg2), "exactly one of {chunk} or {range} required");
} }
return; return;
} }
@@ -1664,13 +1665,14 @@ void ex_lua(exarg_T *const eap)
xfree(code); xfree(code);
return; return;
} }
// When =expr is used transform it to vim.print(expr)
// ":lua {code}", ":={expr}" or ":lua ={expr}"
//
// When "=expr" is used transform it to "vim.print(expr)".
if (eap->cmdidx == CMD_equal || code[0] == '=') { if (eap->cmdidx == CMD_equal || code[0] == '=') {
size_t off = (eap->cmdidx == CMD_equal) ? 0 : 1; size_t off = (eap->cmdidx == CMD_equal) ? 0 : 1;
len += sizeof("vim.print()") - 1 - off; len += sizeof("vim.print()") - 1 - off;
// code_buf needs to be 1 char larger then len for null byte in the end. // `nlua_typval_exec` doesn't expect NUL-terminated string so `len` must end before NUL byte.
// lua nlua_typval_exec doesn't expect null terminated string so len
// needs to end before null byte.
char *code_buf = xmallocz(len); char *code_buf = xmallocz(len);
vim_snprintf(code_buf, len + 1, "vim.print(%s)", code + off); vim_snprintf(code_buf, len + 1, "vim.print(%s)", code + off);
xfree(code); xfree(code);
@@ -1682,11 +1684,11 @@ void ex_lua(exarg_T *const eap)
xfree(code); xfree(code);
} }
/// Run lua string for each line in range /// Executes Lua code for-each line in a buffer range.
/// ///
/// Used for :luado. /// Implements `:luado`.
/// ///
/// @param eap Vimscript command being run. /// @param eap Vimscript `:luado {code}` command.
void ex_luado(exarg_T *const eap) void ex_luado(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
@@ -1763,11 +1765,11 @@ void ex_luado(exarg_T *const eap)
redraw_curbuf_later(UPD_NOT_VALID); redraw_curbuf_later(UPD_NOT_VALID);
} }
/// Run lua file /// Executes Lua code from a file location.
/// ///
/// Used for :luafile. /// Implements `:luafile`.
/// ///
/// @param eap Vimscript command being run. /// @param eap Vimscript `:luafile {file}` command.
void ex_luafile(exarg_T *const eap) void ex_luafile(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {

View File

@@ -2014,7 +2014,7 @@ void cmd_source_buffer(const exarg_T *const eap, bool ex_lua)
}; };
if (ex_lua || strequal(curbuf->b_p_ft, "lua") if (ex_lua || strequal(curbuf->b_p_ft, "lua")
|| (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) { || (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) {
char *name = ex_lua ? ":lua (no file)" : ":source (no file)"; char *name = ex_lua ? ":{range}lua" : ":source (no file)";
nlua_source_using_linegetter(get_str_line, (void *)&cookie, name); nlua_source_using_linegetter(get_str_line, (void *)&cookie, name);
} else { } else {
source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)"); source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)");

View File

@@ -22,7 +22,7 @@ local remove_trace = helpers.remove_trace
before_each(clear) before_each(clear)
describe(':lua command', function() describe(':lua', function()
it('works', function() it('works', function()
eq('', exec_capture('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})')) eq('', exec_capture('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})'))
eq({ '', 'TEST' }, api.nvim_buf_get_lines(0, 0, 100, false)) eq({ '', 'TEST' }, api.nvim_buf_get_lines(0, 0, 100, false))
@@ -54,10 +54,11 @@ describe(':lua command', function()
) )
) )
end) end)
it('throws catchable errors', function() it('throws catchable errors', function()
for _, cmd in ipairs({ 'lua', '1lua chunk' }) do for _, cmd in ipairs({ 'lua', '1lua chunk' }) do
eq( eq(
'Vim(lua):E475: Invalid argument: exactly one of {chunk} and {range} required', 'Vim(lua):E475: Invalid argument: exactly one of {chunk} or {range} required',
pcall_err(command, cmd) pcall_err(command, cmd)
) )
end end
@@ -75,9 +76,11 @@ describe(':lua command', function()
) )
eq({ '' }, api.nvim_buf_get_lines(0, 0, 100, false)) eq({ '' }, api.nvim_buf_get_lines(0, 0, 100, false))
end) end)
it('works with NULL errors', function() it('works with NULL errors', function()
eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)')) eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)'))
end) end)
it('accepts embedded NLs without heredoc', function() it('accepts embedded NLs without heredoc', function()
-- Such code is usually used for `:execute 'lua' {generated_string}`: -- Such code is usually used for `:execute 'lua' {generated_string}`:
-- heredocs do not work in this case. -- heredocs do not work in this case.
@@ -89,12 +92,14 @@ describe(':lua command', function()
]]) ]])
eq({ '', 'ETTS', 'TTSE', 'STTE' }, api.nvim_buf_get_lines(0, 0, 100, false)) eq({ '', 'ETTS', 'TTSE', 'STTE' }, api.nvim_buf_get_lines(0, 0, 100, false))
end) end)
it('preserves global and not preserves local variables', function() it('preserves global and not preserves local variables', function()
eq('', exec_capture('lua gvar = 42')) eq('', exec_capture('lua gvar = 42'))
eq('', exec_capture('lua local lvar = 100500')) eq('', exec_capture('lua local lvar = 100500'))
eq(NIL, fn.luaeval('lvar')) eq(NIL, fn.luaeval('lvar'))
eq(42, fn.luaeval('gvar')) eq(42, fn.luaeval('gvar'))
end) end)
it('works with long strings', function() it('works with long strings', function()
local s = ('x'):rep(100500) local s = ('x'):rep(100500)
@@ -199,17 +204,26 @@ describe(':lua command', function()
) )
end) end)
it('works with range in current buffer', function() it('with range', function()
local screen = Screen.new(40, 10) local screen = Screen.new(40, 10)
screen:attach() screen:attach()
api.nvim_buf_set_lines(0, 0, 0, 0, { 'function x() print "hello" end', 'x()' }) api.nvim_buf_set_lines(0, 0, 0, 0, { 'nonsense', 'function x() print "hello" end', 'x()' })
feed(':1,2lua<CR>')
-- ":{range}lua" fails on invalid Lua code.
eq(
[[:{range}lua: Vim(lua):E5107: Error loading lua [string ":{range}lua"]:0: '=' expected near '<eof>']],
pcall_err(command, '1lua')
)
-- ":{range}lua" executes valid Lua code.
feed(':2,3lua<CR>')
screen:expect { screen:expect {
grid = [[ grid = [[
nonsense |
function x() print "hello" end | function x() print "hello" end |
x() | x() |
^ | ^ |
{1:~ }|*6 {1:~ }|*5
hello | hello |
]], ]],
attr_ids = { attr_ids = {