aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2019-06-29 20:15:12 +0200
committerBjörn Linse <bjorn.linse@gmail.com>2019-08-05 13:19:44 +0200
commitd3a7bdefb0782179433f42f8be8a35816a04f68e (patch)
treedf8992fbe0d92ba525166f436bf625e44a6c37c8
parent4c35e6fe6734050b2e633aba330b0e389835fbc4 (diff)
downloadrneovim-d3a7bdefb0782179433f42f8be8a35816a04f68e.tar.gz
rneovim-d3a7bdefb0782179433f42f8be8a35816a04f68e.tar.bz2
rneovim-d3a7bdefb0782179433f42f8be8a35816a04f68e.zip
lua: immediate-callback safe print()
-rw-r--r--src/nvim/lua/executor.c85
-rw-r--r--test/functional/lua/overrides_spec.lua30
2 files changed, 76 insertions, 39 deletions
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 3fd1620845..44d56e770c 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -323,6 +323,42 @@ void executor_exec_lua(const String str, typval_T *const ret_tv)
nlua_pop_typval(lstate, ret_tv);
}
+static void nlua_print_event(void **argv)
+{
+ char *str = argv[0];
+ const size_t len = (size_t)(intptr_t)argv[1]-1; // exclude final NUL
+
+ for (size_t i = 0; i < len;) {
+ const size_t start = i;
+ while (i < len) {
+ switch (str[i]) {
+ case NUL: {
+ str[i] = NL;
+ i++;
+ continue;
+ }
+ case NL: {
+ // TODO(bfredl): use proper multiline msg? Probably should implement
+ // print() in lua in terms of nvim_message(), when it is available.
+ str[i] = NUL;
+ i++;
+ break;
+ }
+ default: {
+ i++;
+ continue;
+ }
+ }
+ break;
+ }
+ msg((char_u *)str + start);
+ }
+ if (len && str[len - 1] == NUL) { // Last was newline
+ msg((char_u *)"");
+ }
+ xfree(str);
+}
+
/// Print as a Vim message
///
/// @param lstate Lua interpreter state.
@@ -362,47 +398,24 @@ static int nlua_print(lua_State *const lstate)
lua_pop(lstate, 1);
}
#undef PRINT_ERROR
- lua_pop(lstate, nargs + 1);
ga_append(&msg_ga, NUL);
- {
- const size_t len = (size_t)msg_ga.ga_len - 1;
- char *const str = (char *)msg_ga.ga_data;
-
- for (size_t i = 0; i < len;) {
- const size_t start = i;
- while (i < len) {
- switch (str[i]) {
- case NUL: {
- str[i] = NL;
- i++;
- continue;
- }
- case NL: {
- str[i] = NUL;
- i++;
- break;
- }
- default: {
- i++;
- continue;
- }
- }
- break;
- }
- msg((char_u *)str + start);
- }
- if (len && str[len - 1] == NUL) { // Last was newline
- msg((char_u *)"");
- }
+
+ if (in_fast_callback) {
+ multiqueue_put(main_loop.events, nlua_print_event,
+ 2, msg_ga.ga_data, msg_ga.ga_len);
+ } else {
+ nlua_print_event((void *[]){ msg_ga.ga_data,
+ (void *)(intptr_t)msg_ga.ga_len });
}
- ga_clear(&msg_ga);
return 0;
+
nlua_print_error:
- emsgf(_("E5114: Error while converting print argument #%i: %.*s"),
- curargidx, (int)errmsg_len, errmsg);
ga_clear(&msg_ga);
- lua_pop(lstate, lua_gettop(lstate));
- return 0;
+ const char *fmt = _("E5114: Error while converting print argument #%i: %.*s");
+ size_t len = (size_t)vim_snprintf((char *)IObuff, IOSIZE, fmt, curargidx,
+ (int)errmsg_len, errmsg);
+ lua_pushlstring(lstate, (char *)IObuff, len);
+ return lua_error(lstate);
}
/// debug.debug: interaction with user while debugging.
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 8f318e3503..c0541eeae9 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -14,6 +14,7 @@ local command = helpers.command
local write_file = helpers.write_file
local redir_exec = helpers.redir_exec
local alter_slashes = helpers.alter_slashes
+local exec_lua = helpers.exec_lua
local screen
@@ -53,11 +54,11 @@ describe('print', function()
v_tblout = setmetatable({}, meta_tblout)
]])
eq('', redir_exec('luafile ' .. fname))
- eq('\nE5114: Error while converting print argument #2: [NULL]',
+ eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: [NULL]',
redir_exec('lua print("foo", v_nilerr, "bar")'))
- eq('\nE5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
+ eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
redir_exec('lua print("foo", v_abcerr, "bar")'))
- eq('\nE5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
+ eq('\nE5105: Error while calling lua chunk: 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()
@@ -76,6 +77,29 @@ describe('print', function()
eq('\nabc ', redir_exec('lua print("abc", "")'))
eq('\nabc def', redir_exec('lua print("abc", "", "def")'))
end)
+ it('defers printing in luv event handlers', function()
+ exec_lua([[
+ local cmd = ...
+ function test()
+ local timer = vim.loop.new_timer()
+ local done = false
+ timer:start(10, 0, function()
+ print("very fast")
+ timer:close()
+ done = true
+ end)
+ -- be kind to slow travis OS X jobs:
+ -- loop until we know for sure the callback has been executed
+ while not done do
+ os.execute(cmd)
+ vim.loop.run("nowait") -- fake os_breakcheck()
+ end
+ print("very slow")
+ vim.api.nvim_command("sleep 1m") -- force deferred event processing
+ end
+ ]], (iswin() and "timeout 1") or "sleep 0.1")
+ eq('\nvery slow\nvery fast',redir_exec('lua test()'))
+ end)
end)
describe('debug.debug', function()