Add v:lua.func() vimL syntax for calling lua

Also simplify error messages when calling lua from vimL.
This commit is contained in:
Björn Linse 2019-10-30 20:53:09 +01:00
parent 18096631b1
commit dab40f43b1
10 changed files with 442 additions and 217 deletions

View File

@ -1737,6 +1737,10 @@ v:lnum Line number for the 'foldexpr' |fold-expr|, 'formatexpr' and
expressions is being evaluated. Read-only when in the
|sandbox|.
*v:lua* *lua-variable*
v:lua Prefix for calling lua functions from expressions.
See |v:lua-call| for more information.
*v:mouse_win* *mouse_win-variable*
v:mouse_win Window number for a mouse click obtained with |getchar()|.
First window has number 1, like with |winnr()|. The value is

View File

@ -326,6 +326,38 @@ Note: second argument to `luaeval` undergoes VimL to Lua conversion
Return value is also always converted. When converting,
|msgpack-special-dict|s are treated specially.
==============================================================================
v:lua function calls *v:lua-call*
The special prefix `v:lua` can be used in vimL expressions to call lua
functions which are global or nested inside global tables. The expression
`v:lua.func(arg1, arg2)` is equivalent to executing the lua code
`return func(...)` where the args have been converted to lua values. In addition
`v:lua.somemod.func(args)` will work like `return somemod.func(...)` .
`v:lua` can also be used in function options like 'omnifunc'. As an
example, consider the following lua implementation of an omnifunc: >
function mymod.omnifunc(findstart, base)
if findstart == 1 then
return 0
else
return {'stuff', 'steam', 'strange things'}
end
end
vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omnifunc')
A limitation is that the plugin module ("mymod" in this case) must
be made available as a global.
Note: `v:lua` without a call is not allowed in a vimL expression. Funcrefs
to lua functions cannot be created. The following are errors: >
let g:Myvar = v:lua.myfunc
call SomeFunc(v:lua.mycallback)
let g:foo = v:lua
let g:foo = v:['lua']
==============================================================================
Lua standard modules *lua-stdlib*

View File

@ -422,6 +422,7 @@ static struct vimvar {
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
VV(VV_EXITING, "exiting", VAR_NUMBER, VV_RO),
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
};
#undef VV
@ -433,11 +434,14 @@ static struct vimvar {
#define vv_str vv_di.di_tv.vval.v_string
#define vv_list vv_di.di_tv.vval.v_list
#define vv_dict vv_di.di_tv.vval.v_dict
#define vv_partial vv_di.di_tv.vval.v_partial
#define vv_tv vv_di.di_tv
/// Variable used for v:
static ScopeDictDictItem vimvars_var;
static partial_T *vvlua_partial;
/// v: hashtab
#define vimvarht vimvardict.dv_hashtab
@ -639,6 +643,13 @@ void eval_init(void)
set_vim_var_nr(VV_ECHOSPACE, sc_col - 1);
vimvars[VV_LUA].vv_type = VAR_PARTIAL;
vvlua_partial = xcalloc(1, sizeof(partial_T));
vimvars[VV_LUA].vv_partial = vvlua_partial;
// this value shouldn't be printed, but if it is, do not crash
vvlua_partial->pt_name = xmallocz(0);
vvlua_partial->pt_refcount++;
set_reg_var(0); // default for v:register is not 0 but '"'
}
@ -1313,12 +1324,25 @@ int call_vim_function(
{
int doesrange;
int ret;
int len = (int)STRLEN(func);
partial_T *pt = NULL;
if (len >= 6 && !memcmp(func, "v:lua.", 6)) {
func += 6;
len = check_luafunc_name((const char *)func, false);
if (len == 0) {
ret = FAIL;
goto fail;
}
pt = vvlua_partial;
}
rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
ret = call_func(func, (int)STRLEN(func), rettv, argc, argv, NULL,
ret = call_func(func, len, rettv, argc, argv, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, true, NULL, NULL);
&doesrange, true, pt, NULL);
fail:
if (ret == FAIL) {
tv_clear(rettv);
}
@ -2462,6 +2486,13 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
}
}
if (lp->ll_di != NULL && tv_is_luafunc(&lp->ll_di->di_tv)
&& len == -1 && rettv == NULL) {
tv_clear(&var1);
EMSG2(e_illvar, "v:['lua']");
return NULL;
}
if (lp->ll_di == NULL) {
// Can't add "v:" or "a:" variable.
if (lp->ll_dict == &vimvardict
@ -4699,7 +4730,7 @@ eval_index(
if (evaluate) {
n1 = 0;
if (!empty1 && rettv->v_type != VAR_DICT) {
if (!empty1 && rettv->v_type != VAR_DICT && !tv_is_luafunc(rettv)) {
n1 = tv_get_number(&var1);
tv_clear(&var1);
}
@ -4823,7 +4854,7 @@ eval_index(
if (len == -1) {
tv_clear(&var1);
}
if (item == NULL) {
if (item == NULL || tv_is_luafunc(&item->di_tv)) {
return FAIL;
}
@ -6334,7 +6365,7 @@ static char_u *deref_func_name(const char *name, int *lenp,
*/
static int
get_func_tv(
char_u *name, // name of the function
const char_u *name, // name of the function
int len, // length of "name"
typval_T *rettv,
char_u **arg, // argument, pointing to the '('
@ -6590,7 +6621,15 @@ call_func(
rettv->vval.v_number = 0;
error = ERROR_UNKNOWN;
if (!builtin_function((const char *)rfname, -1)) {
if (partial == vvlua_partial) {
if (len > 0) {
error = ERROR_NONE;
executor_call_lua((const char *)funcname, len,
argvars, argcount, rettv);
} else {
error = ERROR_UNKNOWN;
}
} else if (!builtin_function((const char *)rfname, -1)) {
// User defined function.
if (partial != NULL && partial->pt_func != NULL) {
fp = partial->pt_func;
@ -6707,14 +6746,14 @@ call_func(
///
/// @param ermsg must be passed without translation (use N_() instead of _()).
/// @param name function name
static void emsg_funcname(char *ermsg, char_u *name)
static void emsg_funcname(char *ermsg, const char_u *name)
{
char_u *p;
if (*name == K_SPECIAL) {
p = concat_str((char_u *)"<SNR>", name + 3);
} else {
p = name;
p = (char_u *)name;
}
EMSG2(_(ermsg), p);
@ -20168,6 +20207,26 @@ static void check_vars(const char *name, size_t len)
}
}
/// check if special v:lua value for calling lua functions
static bool tv_is_luafunc(typval_T *tv)
{
return tv->v_type == VAR_PARTIAL && tv->vval.v_partial == vvlua_partial;
}
/// check the function name after "v:lua."
static int check_luafunc_name(const char *str, bool paren)
{
const char *p = str;
while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.') {
p++;
}
if (*p != (paren ? '(' : NUL)) {
return 0;
} else {
return (int)(p-str);
}
}
/// Handle expr[expr], expr[expr:expr] subscript and .name lookup.
/// Also handle function call with Funcref variable: func(expr)
/// Can all be combined: dict.func(expr)[idx]['func'](expr)
@ -20181,9 +20240,30 @@ handle_subscript(
{
int ret = OK;
dict_T *selfdict = NULL;
char_u *s;
const char_u *s;
int len;
typval_T functv;
int slen = 0;
bool lua = false;
if (tv_is_luafunc(rettv)) {
if (**arg != '.') {
tv_clear(rettv);
ret = FAIL;
} else {
(*arg)++;
lua = true;
s = (char_u *)(*arg);
slen = check_luafunc_name(*arg, true);
if (slen == 0) {
tv_clear(rettv);
ret = FAIL;
}
(*arg) += slen;
}
}
while (ret == OK
&& (**arg == '['
@ -20200,14 +20280,16 @@ handle_subscript(
// Invoke the function. Recursive!
if (functv.v_type == VAR_PARTIAL) {
pt = functv.vval.v_partial;
s = partial_name(pt);
if (!lua) {
s = partial_name(pt);
}
} else {
s = functv.vval.v_string;
}
} else {
s = (char_u *)"";
}
ret = get_func_tv(s, (int)STRLEN(s), rettv, (char_u **)arg,
ret = get_func_tv(s, lua ? slen : (int)STRLEN(s), rettv, (char_u **)arg,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, pt, selfdict);
@ -22039,8 +22121,19 @@ trans_function_name(
*pp = (char_u *)end;
} else if (lv.ll_tv->v_type == VAR_PARTIAL
&& lv.ll_tv->vval.v_partial != NULL) {
name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
*pp = (char_u *)end;
if (lv.ll_tv->vval.v_partial == vvlua_partial && *end == '.') {
len = check_luafunc_name((const char *)end+1, true);
if (len == 0) {
EMSG2(e_invexpr2, "v:lua");
goto theend;
}
name = xmallocz(len);
memcpy(name, end+1, len);
*pp = (char_u *)end+1+len;
} else {
name = vim_strsave(partial_name(lv.ll_tv->vval.v_partial));
*pp = (char_u *)end;
}
if (partial != NULL) {
*partial = lv.ll_tv->vval.v_partial;
}

View File

@ -117,6 +117,7 @@ typedef enum {
VV_TYPE_BOOL,
VV_ECHOSPACE,
VV_EXITING,
VV_LUA,
} VimVarIndex;
/// All recognized msgpack types

View File

@ -48,9 +48,6 @@ typedef struct {
# include "lua/executor.c.generated.h"
#endif
/// Name of the run code for use in messages
#define NLUA_EVAL_NAME "<VimL compiled string>"
/// Convert lua error into a Vim error message
///
/// @param lstate Lua interpreter state.
@ -397,29 +394,6 @@ static lua_State *nlua_enter(void)
return lstate;
}
/// Execute lua string
///
/// @param[in] str String to execute.
/// @param[out] ret_tv Location where result will be saved.
///
/// @return Result of the execution.
void executor_exec_lua(const String str, typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
lua_State *const lstate = nlua_enter();
if (luaL_loadbuffer(lstate, str.data, str.size, NLUA_EVAL_NAME)) {
nlua_error(lstate, _("E5104: Error while creating lua chunk: %.*s"));
return;
}
if (lua_pcall(lstate, 0, 1, 0)) {
nlua_error(lstate, _("E5105: Error while calling lua chunk: %.*s"));
return;
}
nlua_pop_typval(lstate, ret_tv);
}
static void nlua_print_event(void **argv)
{
char *str = argv[0];
@ -732,10 +706,6 @@ void executor_eval_lua(const String str, typval_T *const arg,
typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
lua_State *const lstate = nlua_enter();
garray_T str_ga;
ga_init(&str_ga, 1, 80);
#define EVALHEADER "local _A=select(1,...) return ("
const size_t lcmd_len = sizeof(EVALHEADER) - 1 + str.size + 1;
char *lcmd;
@ -748,30 +718,71 @@ void executor_eval_lua(const String str, typval_T *const arg,
memcpy(lcmd + sizeof(EVALHEADER) - 1, str.data, str.size);
lcmd[lcmd_len - 1] = ')';
#undef EVALHEADER
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) {
nlua_error(lstate,
_("E5107: Error while creating lua chunk for luaeval(): %.*s"));
if (lcmd != (char *)IObuff) {
xfree(lcmd);
}
return;
}
typval_exec_lua(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv);
if (lcmd != (char *)IObuff) {
xfree(lcmd);
}
}
if (arg->v_type == VAR_UNKNOWN) {
lua_pushnil(lstate);
void executor_call_lua(const char *str, size_t len, typval_T *const args,
int argcount, typval_T *ret_tv)
FUNC_ATTR_NONNULL_ALL
{
#define CALLHEADER "return "
#define CALLSUFFIX "(...)"
const size_t lcmd_len = sizeof(CALLHEADER) - 1 + len + sizeof(CALLSUFFIX) - 1;
char *lcmd;
if (lcmd_len < IOSIZE) {
lcmd = (char *)IObuff;
} else {
nlua_push_typval(lstate, arg, true);
lcmd = xmalloc(lcmd_len);
}
if (lua_pcall(lstate, 1, 1, 0)) {
nlua_error(lstate,
_("E5108: Error while calling lua chunk for luaeval(): %.*s"));
memcpy(lcmd, CALLHEADER, sizeof(CALLHEADER) - 1);
memcpy(lcmd + sizeof(CALLHEADER) - 1, str, len);
memcpy(lcmd + sizeof(CALLHEADER) - 1 + len, CALLSUFFIX,
sizeof(CALLSUFFIX) - 1);
#undef CALLHEADER
#undef CALLSUFFIX
typval_exec_lua(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv);
if (lcmd != (char *)IObuff) {
xfree(lcmd);
}
}
static void typval_exec_lua(const char *lcmd, size_t lcmd_len, const char *name,
typval_T *const args, int argcount, bool special,
typval_T *ret_tv)
{
if (check_restricted() || check_secure()) {
ret_tv->v_type = VAR_NUMBER;
ret_tv->vval.v_number = 0;
return;
}
nlua_pop_typval(lstate, ret_tv);
lua_State *const lstate = nlua_enter();
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, name)) {
nlua_error(lstate, _("E5107: Error loading lua %.*s"));
return;
}
for (int i = 0; i < argcount; i++) {
if (args[i].v_type == VAR_UNKNOWN) {
lua_pushnil(lstate);
} else {
nlua_push_typval(lstate, &args[i], special);
}
}
if (lua_pcall(lstate, argcount, ret_tv ? 1 : 0, 0)) {
nlua_error(lstate, _("E5108: Error executing lua %.*s"));
return;
}
if (ret_tv) {
nlua_pop_typval(lstate, ret_tv);
}
}
/// Execute lua string
@ -857,9 +868,8 @@ void ex_lua(exarg_T *const eap)
xfree(code);
return;
}
typval_T tv = { .v_type = VAR_UNKNOWN };
executor_exec_lua((String) { .data = code, .size = len }, &tv);
tv_clear(&tv);
typval_exec_lua(code, len, ":lua", NULL, 0, false, NULL);
xfree(code);
}
@ -897,8 +907,8 @@ void ex_luado(exarg_T *const eap)
#undef DOSTART
#undef DOEND
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, NLUA_EVAL_NAME)) {
nlua_error(lstate, _("E5109: Error while creating lua chunk: %.*s"));
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, ":luado")) {
nlua_error(lstate, _("E5109: Error loading lua: %.*s"));
if (lcmd_len >= IOSIZE) {
xfree(lcmd);
}
@ -908,7 +918,7 @@ void ex_luado(exarg_T *const eap)
xfree(lcmd);
}
if (lua_pcall(lstate, 0, 1, 0)) {
nlua_error(lstate, _("E5110: Error while creating lua function: %.*s"));
nlua_error(lstate, _("E5110: Error executing lua: %.*s"));
return;
}
for (linenr_T l = eap->line1; l <= eap->line2; l++) {
@ -919,7 +929,7 @@ void ex_luado(exarg_T *const eap)
lua_pushstring(lstate, (const char *)ml_get_buf(curbuf, l, false));
lua_pushnumber(lstate, (lua_Number)l);
if (lua_pcall(lstate, 2, 1, 0)) {
nlua_error(lstate, _("E5111: Error while calling lua function: %.*s"));
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
break;
}
if (lua_isstring(lstate, -1)) {

View File

@ -155,41 +155,41 @@ describe('luaeval(vim.api.…)', function()
it('errors out correctly when working with API', function()
-- Conversion errors
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua type',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua table',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table',
exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Cannot convert given lua type',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]]))
-- Errors in number of arguments
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 1 argument',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument',
exc_exec([[call luaeval("vim.api.nvim__id()")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 1 argument',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument',
exc_exec([[call luaeval("vim.api.nvim__id(1, 2)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected 2 arguments',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 2 arguments',
exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2, 3)")]]))
-- Error in argument types
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua string',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua string',
exc_exec([[call luaeval("vim.api.nvim_set_var(1, 2)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua number',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua number',
exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Number is not integral',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral',
exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type',
exc_exec([[call luaeval("vim.api.nvim__id_float({[vim.type_idx]=vim.types.dictionary})")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
exc_exec([[call luaeval("vim.api.nvim__id_array(1)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type',
exc_exec([[call luaeval("vim.api.nvim__id_array({[vim.type_idx]=vim.types.dictionary})")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Expected lua table',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
exc_exec([[call luaeval("vim.api.nvim__id_dictionary(1)")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: Unexpected type',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Unexpected type',
exc_exec([[call luaeval("vim.api.nvim__id_dictionary({[vim.type_idx]=vim.types.array})")]]))
-- TODO: check for errors with Tabpage argument
-- TODO: check for errors with Window argument

View File

@ -13,6 +13,7 @@ local source = helpers.source
local dedent = helpers.dedent
local command = helpers.command
local exc_exec = helpers.exc_exec
local pcall_err = helpers.pcall_err
local write_file = helpers.write_file
local redir_exec = helpers.redir_exec
local curbufmeths = helpers.curbufmeths
@ -42,16 +43,16 @@ describe(':lua command', function()
eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false))
end)
it('throws catchable errors', function()
eq([[Vim(lua):E5104: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unexpected symbol near ')']],
exc_exec('lua ()'))
eq([[Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: TEST]],
eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:1: unexpected symbol near ')']],
pcall_err(command, 'lua ()'))
eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: TEST]],
exc_exec('lua error("TEST")'))
eq([[Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: Invalid buffer id]],
eq([[Vim(lua):E5108: Error executing lua [string ":lua"]:1: Invalid buffer id]],
exc_exec('lua vim.api.nvim_buf_set_lines(-10, 1, 1, false, {"TEST"})'))
eq({''}, curbufmeths.get_lines(0, 100, false))
end)
it('works with NULL errors', function()
eq([=[Vim(lua):E5105: Error while calling lua chunk: [NULL]]=],
eq([=[Vim(lua):E5108: Error executing lua [NULL]]=],
exc_exec('lua error(nil)'))
end)
it('accepts embedded NLs without heredoc', function()
@ -74,7 +75,7 @@ describe(':lua command', function()
it('works with long strings', function()
local s = ('x'):rep(100500)
eq('\nE5104: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unfinished string near \'<eof>\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s)))
eq('\nE5107: Error loading lua [string ":lua"]:1: unfinished string near \'<eof>\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s)))
eq({''}, curbufmeths.get_lines(0, -1, false))
eq('', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s)))
@ -82,7 +83,7 @@ describe(':lua command', function()
end)
it('can show multiline error messages', function()
local screen = Screen.new(50,10)
local screen = Screen.new(40,10)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
@ -92,51 +93,51 @@ describe(':lua command', function()
})
feed(':lua error("fail\\nmuch error\\nsuch details")<cr>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{2: }|
{3:E5105: Error while calling lua chunk: [string "<Vi}|
{3:mL compiled string>"]:1: fail} |
{3:much error} |
{3:such details} |
{4:Press ENTER or type command to continue}^ |
]])
screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
{1:~ }|
{2: }|
{3:E5108: Error executing lua [string ":lua}|
{3:"]:1: fail} |
{3:much error} |
{3:such details} |
{4:Press ENTER or type command to continue}^ |
]]}
feed('<cr>')
screen:expect([[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]])
eq('E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: fail\nmuch error\nsuch details', eval('v:errmsg'))
screen:expect{grid=[[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
eq('E5108: Error executing lua [string ":lua"]:1: fail\nmuch error\nsuch details', eval('v:errmsg'))
local status, err = pcall(command,'lua error("some error\\nin a\\nAPI command")')
local expected = 'Vim(lua):E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: some error\nin a\nAPI command'
local expected = 'Vim(lua):E5108: Error executing lua [string ":lua"]:1: some error\nin a\nAPI command'
eq(false, status)
eq(expected, string.sub(err, -string.len(expected)))
feed(':messages<cr>')
screen:expect([[
|
{1:~ }|
{1:~ }|
{1:~ }|
{2: }|
{3:E5105: Error while calling lua chunk: [string "<Vi}|
{3:mL compiled string>"]:1: fail} |
{3:much error} |
{3:such details} |
{4:Press ENTER or type command to continue}^ |
]])
screen:expect{grid=[[
|
{1:~ }|
{1:~ }|
{1:~ }|
{2: }|
{3:E5108: Error executing lua [string ":lua}|
{3:"]:1: fail} |
{3:much error} |
{3:such details} |
{4:Press ENTER or type command to continue}^ |
]]}
end)
end)
@ -167,13 +168,13 @@ describe(':luado command', function()
eq({''}, curbufmeths.get_lines(0, -1, false))
end)
it('fails on errors', function()
eq([[Vim(luado):E5109: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unexpected symbol near ')']],
eq([[Vim(luado):E5109: Error loading lua: [string ":luado"]:1: unexpected symbol near ')']],
exc_exec('luado ()'))
eq([[Vim(luado):E5111: Error while calling lua function: [string "<VimL compiled string>"]:1: attempt to perform arithmetic on global 'liness' (a nil value)]],
eq([[Vim(luado):E5111: Error calling lua: [string ":luado"]:1: attempt to perform arithmetic on global 'liness' (a nil value)]],
exc_exec('luado return liness + 1'))
end)
it('works with NULL errors', function()
eq([=[Vim(luado):E5111: Error while calling lua function: [NULL]]=],
eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=],
exc_exec('luado error(nil)'))
end)
it('fails in sandbox when needed', function()
@ -185,7 +186,7 @@ describe(':luado command', function()
it('works with long strings', function()
local s = ('x'):rep(100500)
eq('\nE5109: Error while creating lua chunk: [string "<VimL compiled string>"]:1: unfinished string near \'<eof>\'', redir_exec(('luado return "%s'):format(s)))
eq('\nE5109: Error loading lua: [string ":luado"]:1: unfinished string near \'<eof>\'', redir_exec(('luado return "%s'):format(s)))
eq({''}, curbufmeths.get_lines(0, -1, false))
eq('', redir_exec(('luado return "%s"'):format(s)))

View File

@ -1,13 +1,17 @@
-- Test suite for testing luaeval() function
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local redir_exec = helpers.redir_exec
local pcall_err = helpers.pcall_err
local exc_exec = helpers.exc_exec
local exec_lua = helpers.exec_lua
local command = helpers.command
local meths = helpers.meths
local funcs = helpers.funcs
local clear = helpers.clear
local eval = helpers.eval
local feed = helpers.feed
local NIL = helpers.NIL
local eq = helpers.eq
@ -186,9 +190,9 @@ describe('luaeval()', function()
exc_exec('call luaeval("{1, foo=2}")'))
eq("Vim(call):E5101: Cannot convert given lua type",
exc_exec('call luaeval("vim.api.nvim_buf_get_lines")'))
startswith("Vim(call):E5107: Error while creating lua chunk for luaeval(): ",
startswith("Vim(call):E5107: Error loading lua [string \"luaeval()\"]:",
exc_exec('call luaeval("1, 2, 3")'))
startswith("Vim(call):E5108: Error while calling lua chunk for luaeval(): ",
startswith("Vim(call):E5108: Error executing lua [string \"luaeval()\"]:",
exc_exec('call luaeval("(nil)()")'))
eq("Vim(call):E5101: Cannot convert given lua type",
exc_exec('call luaeval("{42, vim.api}")'))
@ -237,19 +241,99 @@ describe('luaeval()', function()
it('errors out correctly when doing incorrect things in lua', function()
-- Conversion errors
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: attempt to call field \'xxx_nonexistent_key_xxx\' (a nil value)',
exc_exec([[call luaeval("vim.xxx_nonexistent_key_xxx()")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [string "<VimL compiled string>"]:1: ERROR',
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: ERROR',
exc_exec([[call luaeval("error('ERROR')")]]))
eq('Vim(call):E5108: Error while calling lua chunk for luaeval(): [NULL]',
eq('Vim(call):E5108: Error executing lua [NULL]',
exc_exec([[call luaeval("error(nil)")]]))
end)
it('does not leak memory when called with too long line',
function()
local s = ('x'):rep(65536)
eq('Vim(call):E5107: Error while creating lua chunk for luaeval(): [string "<VimL compiled string>"]:1: unexpected symbol near \')\'',
eq('Vim(call):E5107: Error loading lua [string "luaeval()"]:1: unexpected symbol near \')\'',
exc_exec([[call luaeval("(']] .. s ..[[' + )")]]))
eq(s, funcs.luaeval('"' .. s .. '"'))
end)
end)
describe('v:lua', function()
before_each(function()
exec_lua([[
function _G.foo(a,b,n)
_G.val = n
return a+b
end
mymod = {}
function mymod.noisy(name)
vim.api.nvim_set_current_line("hey "..name)
end
function mymod.crashy()
nonexistent()
end
function mymod.omni(findstart, base)
if findstart == 1 then
return 5
else
if base == 'st' then
return {'stuff', 'steam', 'strange things'}
end
end
end
vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omni')
]])
end)
it('works in expressions', function()
eq(7, eval('v:lua.foo(3,4,v:null)'))
eq(true, exec_lua([[return _G.val == vim.NIL]]))
eq(NIL, eval('v:lua.mymod.noisy("eval")'))
eq("hey eval", meths.get_current_line())
eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)",
pcall_err(eval, 'v:lua.mymod.crashy()'))
end)
it('works in :call', function()
command(":call v:lua.mymod.noisy('command')")
eq("hey command", meths.get_current_line())
eq("Vim(call):E5108: Error executing lua [string \"<nvim>\"]:10: attempt to call global 'nonexistent' (a nil value)",
pcall_err(command, 'call v:lua.mymod.crashy()'))
end)
it('works in func options', function()
local screen = Screen.new(60, 8)
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {background = Screen.colors.WebGray},
[3] = {background = Screen.colors.LightMagenta},
[4] = {bold = true},
[5] = {bold = true, foreground = Screen.colors.SeaGreen4},
})
screen:attach()
feed('isome st<c-x><c-o>')
screen:expect{grid=[[
some stuff^ |
{1:~ }{2: stuff }{1: }|
{1:~ }{3: steam }{1: }|
{1:~ }{3: strange things }{1: }|
{1:~ }|
{1:~ }|
{1:~ }|
{4:-- Omni completion (^O^N^P) }{5:match 1 of 3} |
]]}
end)
it('throw errors for invalid use', function()
eq('Vim(let):E15: Invalid expression: v:lua.func', pcall_err(command, "let g:Func = v:lua.func"))
eq('Vim(let):E15: Invalid expression: v:lua', pcall_err(command, "let g:Func = v:lua"))
eq("Vim(let):E15: Invalid expression: v:['lua']", pcall_err(command, "let g:Func = v:['lua']"))
eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()"))
eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()"))
eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'"))
eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'"))
end)
end)

View File

@ -54,11 +54,12 @@ describe('print', function()
v_tblout = setmetatable({}, meta_tblout)
]])
eq('', redir_exec('luafile ' .. fname))
eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: [NULL]',
-- TODO(bfredl): these look weird, print() should not use "E5114:" style errors..
eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: [NULL]',
redir_exec('lua print("foo", v_nilerr, "bar")'))
eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
redir_exec('lua print("foo", v_abcerr, "bar")'))
eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
redir_exec('lua print("foo", v_tblout, "bar")'))
end)
it('prints strings with NULs and NLs correctly', function()
@ -156,7 +157,8 @@ describe('debug.debug', function()
lua_debug> ^ |
]])
feed('<C-c>')
screen:expect([[
screen:expect{grid=[[
{0:~ }|
{0:~ }|
{0:~ }|
{0:~ }|
@ -167,11 +169,10 @@ describe('debug.debug', function()
lua_debug> print("TEST") |
TEST |
|
{E:E5105: Error while calling lua chunk: [string "<VimL }|
{E:compiled string>"]:5: attempt to perform arithmetic o}|
{E:n local 'a' (a nil value)} |
{E:E5108: Error executing lua [string ":lua"]:5: attempt}|
{E: to perform arithmetic on local 'a' (a nil value)} |
Interrupt: {cr:Press ENTER or type command to continue}^ |
]])
]]}
feed('<C-l>:lua Test()\n')
screen:expect([[
{0:~ }|
@ -190,7 +191,8 @@ describe('debug.debug', function()
lua_debug> ^ |
]])
feed('\n')
screen:expect([[
screen:expect{grid=[[
{0:~ }|
{0:~ }|
{0:~ }|
{0:~ }|
@ -201,11 +203,10 @@ describe('debug.debug', function()
{0:~ }|
nil |
lua_debug> |
{E:E5105: Error while calling lua chunk: [string "<VimL }|
{E:compiled string>"]:5: attempt to perform arithmetic o}|
{E:n local 'a' (a nil value)} |
{E:E5108: Error executing lua [string ":lua"]:5: attempt}|
{E: to perform arithmetic on local 'a' (a nil value)} |
{cr:Press ENTER or type command to continue}^ |
]])
]]}
end)
it("can be safely exited with 'cont'", function()

View File

@ -747,7 +747,7 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
]], messages={{
content = {{'E5105: Error while calling lua chunk: [string "<VimL compiled string>"]:1: such\nmultiline\nerror', 2}},
content = {{'E5108: Error executing lua [string ":lua"]:1: such\nmultiline\nerror', 2}},
kind = "lua_error"
}}}
end)
@ -1146,97 +1146,96 @@ aliquip ex ea commodo consequat.]])
it('handles wrapped lines with line scroll', function()
feed(':lua error(_G.x)<cr>')
screen:expect{grid=[[
{2:E5105: Error while calling lua chun}|
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:E5108: Error executing lua [string }|
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{4:-- More --}^ |
]]}
feed('j')
screen:expect{grid=[[
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{2:Ut enim ad minim veniam, quis nostr}|
{4:-- More --}^ |
]]}
feed('k')
screen:expect{grid=[[
{2:E5105: Error while calling lua chun}|
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:E5108: Error executing lua [string }|
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{4:-- More --}^ |
]]}
feed('j')
screen:expect{grid=[[
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{2:Ut enim ad minim veniam, quis nostr}|
{4:-- More --}^ |
]]}
end)
it('handles wrapped lines with page scroll', function()
feed(':lua error(_G.x)<cr>')
screen:expect{grid=[[
{2:E5105: Error while calling lua chun}|
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:E5108: Error executing lua [string }|
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{4:-- More --}^ |
]]}
feed('d')
screen:expect{grid=[[
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{2:Ut enim ad minim veniam, quis nostr}|
{2:ud xercitation} |
{2:ullamco laboris nisi ut} |
{4:-- More --}^ |
{2:aliquip ex ea commodo consequat.} |
{4:Press ENTER or type command to cont}|
{4:inue}^ |
]]}
feed('u')
screen:expect{grid=[[
{2:E5105: Error while calling lua chun}|
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:E5108: Error executing lua [string }|
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{4:-- More --}^ |
]]}
feed('d')
screen:expect{grid=[[
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{2:Ut enim ad minim veniam, quis nostr}|
{2:ud xercitation} |
{2:ullamco laboris nisi ut} |
{2:aliquip ex ea commodo consequat.} |
{4:-- More --}^ |
]]}
end)
@ -1246,49 +1245,49 @@ aliquip ex ea commodo consequat.]])
feed(':lua error(_G.x)<cr>')
screen:expect{grid=[[
{3:E5105: Error while calling lua chun}|
{3:k: [string "<VimL compiled string>"}|
{3:]:1: Lorem ipsum dolor sit amet, co}|
{3:nsectetur}{5: }|
{3:E5108: Error executing lua [string }|
{3:":lua"]:1: Lorem ipsum dolor sit am}|
{3:et, consectetur}{5: }|
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{6:-- More --}{5:^ }|
]]}
feed('j')
screen:expect{grid=[[
{3:k: [string "<VimL compiled string>"}|
{3:]:1: Lorem ipsum dolor sit amet, co}|
{3:nsectetur}{5: }|
{3:":lua"]:1: Lorem ipsum dolor sit am}|
{3:et, consectetur}{5: }|
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{3:Ut enim ad minim veniam, quis nostr}|
{6:-- More --}{5:^ }|
]]}
feed('k')
screen:expect{grid=[[
{3:E5105: Error while calling lua chun}|
{3:k: [string "<VimL compiled string>"}|
{3:]:1: Lorem ipsum dolor sit amet, co}|
{3:nsectetur}{5: }|
{3:E5108: Error executing lua [string }|
{3:":lua"]:1: Lorem ipsum dolor sit am}|
{3:et, consectetur}{5: }|
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{6:-- More --}{5:^ }|
]]}
feed('j')
screen:expect{grid=[[
{3:k: [string "<VimL compiled string>"}|
{3:]:1: Lorem ipsum dolor sit amet, co}|
{3:nsectetur}{5: }|
{3:":lua"]:1: Lorem ipsum dolor sit am}|
{3:et, consectetur}{5: }|
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{3:Ut enim ad minim veniam, quis nostr}|
{6:-- More --}{5:^ }|
]]}
end)
@ -1297,46 +1296,46 @@ aliquip ex ea commodo consequat.]])
command("hi MsgArea guisp=Yellow")
feed(':lua error(_G.x)<cr>')
screen:expect{grid=[[
{3:E5105: Error while calling lua chun}|
{3:k: [string "<VimL compiled string>"}|
{3:]:1: Lorem ipsum dolor sit amet, co}|
{3:nsectetur}{5: }|
{3:E5108: Error executing lua [string }|
{3:":lua"]:1: Lorem ipsum dolor sit am}|
{3:et, consectetur}{5: }|
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{6:-- More --}{5:^ }|
]]}
feed('d')
screen:expect{grid=[[
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{3:Ut enim ad minim veniam, quis nostr}|
{3:ud xercitation}{5: }|
{3:ullamco laboris nisi ut}{5: }|
{6:-- More --}{5:^ }|
{3:aliquip ex ea commodo consequat.}{5: }|
{6:Press ENTER or type command to cont}|
{6:inue}{5:^ }|
]]}
feed('u')
screen:expect{grid=[[
{3:E5105: Error while calling lua chun}|
{3:k: [string "<VimL compiled string>"}|
{3:]:1: Lorem ipsum dolor sit amet, co}|
{3:nsectetur}{5: }|
{3:E5108: Error executing lua [string }|
{3:":lua"]:1: Lorem ipsum dolor sit am}|
{3:et, consectetur}{5: }|
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{6:-- More --}{5:^ }|
]]}
feed('d')
screen:expect{grid=[[
{3:adipisicing elit, sed do eiusmod te}|
{3:mpor}{5: }|
{3:incididunt ut labore et dolore magn}|
{3:a aliqua.}{5: }|
{3:Ut enim ad minim veniam, quis nostr}|
{3:ud xercitation}{5: }|
{3:ullamco laboris nisi ut}{5: }|
{3:aliquip ex ea commodo consequat.}{5: }|
{6:-- More --}{5:^ }|
]]}
end)
@ -1473,23 +1472,23 @@ aliquip ex ea commodo consequat.]])
it('can be resized', function()
feed(':lua error(_G.x)<cr>')
screen:expect{grid=[[
{2:E5105: Error while calling lua chun}|
{2:k: [string "<VimL compiled string>"}|
{2:]:1: Lorem ipsum dolor sit amet, co}|
{2:nsectetur} |
{2:E5108: Error executing lua [string }|
{2:":lua"]:1: Lorem ipsum dolor sit am}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusmod te}|
{2:mpor} |
{2:incididunt ut labore et dolore magn}|
{2:a aliqua.} |
{4:-- More --}^ |
]]}
-- responds to resize, but text is not reflown
screen:try_resize(45, 5)
screen:expect{grid=[[
{2:nsectetur} |
{2:adipisicing elit, sed do eiusmod te} |
{2:mpor} |
{2:incididunt ut labore et dolore magn} |
{2:a aliqua.} |
{4:-- More --}^ |
]]}
@ -1497,14 +1496,14 @@ aliquip ex ea commodo consequat.]])
-- text is not reflown; existing lines get cut
screen:try_resize(30, 12)
screen:expect{grid=[[
{2:E5105: Error while calling lua}|
{2:k: [string "<VimL compiled str}|
{2:]:1: Lorem ipsum dolor sit ame}|
{2:nsectetur} |
{2:E5108: Error executing lua [st}|
{2:":lua"]:1: Lorem ipsum dolor s}|
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusm}|
{2:mpore} |
{2:incididunt ut labore et dolore}|
{2: magn} |
{2:a aliqua.} |
|
|
|
|
@ -1515,18 +1514,18 @@ aliquip ex ea commodo consequat.]])
-- wrapped at the new screen size.
feed('<cr>')
screen:expect{grid=[[
{2:k: [string "<VimL compiled str}|
{2:]:1: Lorem ipsum dolor sit ame}|
{2:nsectetur} |
{2:et, consectetur} |
{2:adipisicing elit, sed do eiusm}|
{2:mpore} |
{2:incididunt ut labore et dolore}|
{2: magna aliqua.} |
{2:a aliqua.} |
{2:Ut enim ad minim veniam, quis }|
{2:nostrud xercitation} |
{2:ullamco laboris nisi ut} |
{2:aliquip ex ea commodo consequa}|
{4:-- More --}^ |
{2:t.} |
{4:Press ENTER or type command to}|
{4: continue}^ |
]]}
feed('q')