diff options
-rw-r--r-- | runtime/doc/lua.txt | 15 | ||||
-rw-r--r-- | runtime/doc/repeat.txt | 8 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 30 | ||||
-rw-r--r-- | src/nvim/runtime.c | 2 | ||||
-rw-r--r-- | test/functional/lua/commands_spec.lua | 26 |
5 files changed, 49 insertions, 32 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index fecdfd9bd0..7aa2fd5a6f 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -255,10 +255,13 @@ arguments separated by " " (space) instead of "\t" (tab). :lua =jit.version < :{range}lua - Executes the |[range]| in the current buffer as Lua code. Unlike |:source|, - this will execute the specified lines regardless of the extension or - |'filetype'| of the buffer. + Executes buffer lines in {range} as Lua code. Unlike |:source|, this + always treats the lines as Lua code. + Example: select the following code and type ":lua<Enter>" to execute it: >lua + print(string.format( + 'unix time: %s', os.time())) +< *:lua-heredoc* :lua << [trim] [{endmarker}] {script} @@ -271,10 +274,8 @@ arguments separated by " " (space) instead of "\t" (tab). function! CurrentLineInfo() lua << EOF local linenr = vim.api.nvim_win_get_cursor(0)[1] - local curline = vim.api.nvim_buf_get_lines( - 0, linenr - 1, linenr, false)[1] - print(string.format("Current line [%d] has %d bytes", - linenr, #curline)) + local curline = vim.api.nvim_buf_get_lines(0, linenr - 1, linenr, false)[1] + print(string.format('Line [%d] has %d bytes', linenr, #curline)) EOF endfunction < diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 726d7a9591..ae827fa06f 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -192,11 +192,11 @@ Using Vim scripts *using-scripts* For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. *: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]. - If no [file], the current buffer is used, and it is - treated as Lua code if its 'filetype' is "lua" or its - file name ends with ".lua". + If no [file], the current buffer is used and treated + as Lua code if 'filetype' is "lua" or its filename + ends with ".lua". Triggers the |SourcePre| autocommand. *:source!* :[range]so[urce]! {file} diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 3139e924a1..62e82175c3 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1641,19 +1641,20 @@ bool nlua_is_deferred_safe(void) 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) FUNC_ATTR_NONNULL_ALL { + // ":{range}lua" if (eap->addr_count > 0 || *eap->arg == NUL) { if (eap->addr_count > 0 && *eap->arg == NUL) { cmd_source_buffer(eap, true); } else { - semsg(_(e_invarg2), "exactly one of {chunk} and {range} required"); + semsg(_(e_invarg2), "exactly one of {chunk} or {range} required"); } return; } @@ -1664,13 +1665,14 @@ void ex_lua(exarg_T *const eap) xfree(code); 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] == '=') { size_t off = (eap->cmdidx == CMD_equal) ? 0 : 1; len += sizeof("vim.print()") - 1 - off; - // code_buf needs to be 1 char larger then len for null byte in the end. - // lua nlua_typval_exec doesn't expect null terminated string so len - // needs to end before null byte. + // `nlua_typval_exec` doesn't expect NUL-terminated string so `len` must end before NUL byte. char *code_buf = xmallocz(len); vim_snprintf(code_buf, len + 1, "vim.print(%s)", code + off); xfree(code); @@ -1682,11 +1684,11 @@ void ex_lua(exarg_T *const eap) 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) FUNC_ATTR_NONNULL_ALL { @@ -1763,11 +1765,11 @@ void ex_luado(exarg_T *const eap) 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) FUNC_ATTR_NONNULL_ALL { diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 77a22b6fd1..98e9d6c9e6 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -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") || (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); } else { source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)"); diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua index 083f6f3541..b759d0e2c4 100644 --- a/test/functional/lua/commands_spec.lua +++ b/test/functional/lua/commands_spec.lua @@ -22,7 +22,7 @@ local remove_trace = helpers.remove_trace before_each(clear) -describe(':lua command', function() +describe(':lua', function() it('works', function() 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)) @@ -54,10 +54,11 @@ describe(':lua command', function() ) ) end) + it('throws catchable errors', function() for _, cmd in ipairs({ 'lua', '1lua chunk' }) do 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) ) end @@ -75,9 +76,11 @@ describe(':lua command', function() ) eq({ '' }, api.nvim_buf_get_lines(0, 0, 100, false)) end) + it('works with NULL errors', function() eq([=[Vim(lua):E5108: Error executing lua [NULL]]=], exc_exec('lua error(nil)')) end) + it('accepts embedded NLs without heredoc', function() -- Such code is usually used for `:execute 'lua' {generated_string}`: -- 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)) end) + it('preserves global and not preserves local variables', function() eq('', exec_capture('lua gvar = 42')) eq('', exec_capture('lua local lvar = 100500')) eq(NIL, fn.luaeval('lvar')) eq(42, fn.luaeval('gvar')) end) + it('works with long strings', function() local s = ('x'):rep(100500) @@ -199,17 +204,26 @@ describe(':lua command', function() ) end) - it('works with range in current buffer', function() + it('with range', function() local screen = Screen.new(40, 10) screen:attach() - api.nvim_buf_set_lines(0, 0, 0, 0, { 'function x() print "hello" end', 'x()' }) - feed(':1,2lua<CR>') + api.nvim_buf_set_lines(0, 0, 0, 0, { 'nonsense', 'function x() print "hello" end', 'x()' }) + + -- ":{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 { grid = [[ + nonsense | function x() print "hello" end | x() | ^ | - {1:~ }|*6 + {1:~ }|*5 hello | ]], attr_ids = { |