From d33aaa0f5f96afb1608a4a3eb2057da956a24b2b Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sun, 23 Jun 2019 20:10:28 +0200 Subject: libluv: use luv_set_callback to control callback execution Disable the use of deferred API functions in a fast lua callback Correctly display error messages from a fast lua callback --- test/functional/lua/loop_spec.lua | 100 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 5 deletions(-) (limited to 'test/functional/lua/loop_spec.lua') diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index 8cc54e8c13..3b3b81f886 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -1,11 +1,15 @@ -- Test suite for testing interactions with API bindings local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') local funcs = helpers.funcs local meths = helpers.meths local clear = helpers.clear local sleep = helpers.sleep +local feed = helpers.feed local eq = helpers.eq +local eval = helpers.eval local matches = helpers.matches +local exec_lua = helpers.exec_lua before_each(clear) @@ -17,7 +21,7 @@ describe('vim.loop', function() end) it('timer', function() - meths.execute_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) + exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) local code=[[ local loop = vim.loop @@ -27,14 +31,14 @@ describe('vim.loop', function() local this = coroutine.running() assert(this) local timer = loop.new_timer() - timer:start(ms, 0, function () + timer:start(ms, 0, vim.schedule_wrap(function () timer:close() touch = touch + 1 coroutine.resume(this) touch = touch + 1 assert(touch==3) vim.api.nvim_set_var("coroutine_cnt_1", touch) - end) + end)) coroutine.yield() touch = touch + 1 return touch @@ -47,9 +51,95 @@ describe('vim.loop', function() ]] eq(0, meths.get_var('coroutine_cnt')) - meths.execute_lua(code, {}) - sleep(20) + exec_lua(code) + sleep(50) eq(2, meths.get_var('coroutine_cnt')) eq(3, meths.get_var('coroutine_cnt_1')) end) + + it('is API safe', function() + local screen = Screen.new(50,10) + screen:attach() + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + [5] = {bold = true}, + }) + + -- deferred API functions are disabled, as their safety can't be guaranteed + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(20, 0, function () + timer:close() + vim.api.nvim_set_var("valid", true) + vim.api.nvim_command("echomsg 'howdy'") + end) + ]]) + + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:Error executing luv callback:} | + {3:[string ""]:4: E5560: nvim_set_var must not }| + {3:be called in a lua loop callback} | + {4:Press ENTER or type command to continue}^ | + ]]) + feed('') + eq(false, eval("get(g:, 'valid', v:false)")) + + -- callbacks can be scheduled to be executed in the main event loop + -- where the entire API is available + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(20, 0, vim.schedule_wrap(function () + timer:close() + vim.api.nvim_set_var("valid", true) + vim.api.nvim_command("echomsg 'howdy'") + end)) + ]]) + + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + howdy | + ]]) + eq(true, eval("get(g:, 'valid', v:false)")) + + -- fast (not deferred) API functions are allowed to be called directly + exec_lua([[ + local timer = vim.loop.new_timer() + timer:start(20, 0, function () + timer:close() + -- input is queued for processing after the callback returns + vim.api.nvim_input("isneaky") + _G.mode = vim.api.nvim_get_mode() + end) + ]]) + screen:expect([[ + sneaky^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {5:-- INSERT --} | + ]]) + eq({blocking=false, mode='n'}, exec_lua("return _G.mode")) + end) end) -- cgit From 99f24dfbed84cea24fc1d8bb80ab10a2dd3eca0b Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Wed, 26 Jun 2019 14:33:48 +0200 Subject: make vim.loop == require'luv' This avoids initializing libluv a second time if a plugin invokes require'luv'. It is probably not an issue, but better to be safe. --- test/functional/lua/loop_spec.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test/functional/lua/loop_spec.lua') diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua index 3b3b81f886..cd3b935e1a 100644 --- a/test/functional/lua/loop_spec.lua +++ b/test/functional/lua/loop_spec.lua @@ -142,4 +142,8 @@ describe('vim.loop', function() ]]) eq({blocking=false, mode='n'}, exec_lua("return _G.mode")) end) + + it("is equal to require('luv')", function() + eq(true, exec_lua("return vim.loop == require('luv')")) + end) end) -- cgit