From c83926cd0aa5720e88e84fa3fae3c0e689cca3ef Mon Sep 17 00:00:00 2001 From: George Zhao Date: Mon, 10 Jun 2019 20:13:18 +0800 Subject: [PATCH] lua: introduce vim.loop (expose libuv event-loop) #10123 Co-authored-by: Andrey Popp <8mayday@gmail.com> closes #9546 closes #10084 --- CMakeLists.txt | 3 ++ cmake/FindLibLUV.cmake | 32 ++++++++++++++++ src/nvim/CMakeLists.txt | 1 + src/nvim/lua/executor.c | 7 ++++ test/functional/lua/loop_spec.lua | 55 +++++++++++++++++++++++++++ third-party/CMakeLists.txt | 7 +++- third-party/cmake/BuildLuarocks.cmake | 5 ++- third-party/cmake/BuildLuv.cmake | 25 +++++++++++- 8 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 cmake/FindLibLUV.cmake create mode 100644 test/functional/lua/loop_spec.lua diff --git a/CMakeLists.txt b/CMakeLists.txt index 43281dee2c..7d2314a418 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,6 +385,9 @@ include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS}) find_package(Msgpack 1.0.0 REQUIRED) include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS}) +find_package(LibLUV 1.29.1 REQUIRED) +include_directories(SYSTEM ${LIBLUV_INCLUDE_DIRS}) + # Note: The test lib requires LuaJIT; it will be skipped if LuaJIT is missing. option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF) diff --git a/cmake/FindLibLUV.cmake b/cmake/FindLibLUV.cmake new file mode 100644 index 0000000000..d8ce9264c3 --- /dev/null +++ b/cmake/FindLibLUV.cmake @@ -0,0 +1,32 @@ +# - Try to find luv +# Once done this will define +# LIBLUV_FOUND - System has libluv +# LIBLUV_INCLUDE_DIRS - The libluv include directories +# LIBLUV_LIBRARIES - The libraries needed to use libluv + +find_path(LIBLUV_INCLUDE_DIR luv/luv.h + PATHS ${PC_LIBLUV_INCLUDEDIR} ${PC_LIBLUV_INCLUDE_DIRS} + ${LIMIT_SEARCH}) + +# If we're asked to use static linkage, add libluv.a as a preferred library name. +if(LIBLUV_USE_STATIC) + list(APPEND LIBLUV_NAMES + "${CMAKE_STATIC_LIBRARY_PREFIX}luv${CMAKE_STATIC_LIBRARY_SUFFIX}") +endif() + +list(APPEND LIBLUV_NAMES luv) + +find_library(LIBLUV_LIBRARY NAMES ${LIBLUV_NAMES} + HINTS ${PC_LIBLUV_LIBDIR} ${PC_LIBLUV_LIBRARY_DIRS} + ${LIMIT_SEARCH}) + +set(LIBLUV_LIBRARIES ${LIBLUV_LIBRARY}) +set(LIBLUV_INCLUDE_DIRS ${LIBLUV_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set LIBLUV_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(libluv DEFAULT_MSG + LIBLUV_LIBRARY LIBLUV_INCLUDE_DIR) + +mark_as_advanced(LIBLUV_INCLUDE_DIR LIBLUV_LIBRARY) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 8abc43c2aa..77c5bf59e4 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -383,6 +383,7 @@ endif() # Put these last on the link line, since multiple things may depend on them. list(APPEND NVIM_LINK_LIBRARIES + ${LIBLUV_LIBRARIES} ${LIBUV_LIBRARIES} ${MSGPACK_LIBRARIES} ${LIBVTERM_LIBRARIES} diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index df08a9dd87..8cb282356a 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -31,6 +31,8 @@ #include "nvim/lua/executor.h" #include "nvim/lua/converter.h" +#include "luv/luv.h" + typedef struct { Error err; String lua_err_str; @@ -176,6 +178,11 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, &nlua_schedule); lua_setfield(lstate, -2, "schedule"); + // vim.loop + luv_set_loop(lstate, &main_loop.uv); + luaopen_luv(lstate); + lua_setfield(lstate, -2, "loop"); + lua_setglobal(lstate, "vim"); return 0; } diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua new file mode 100644 index 0000000000..8cc54e8c13 --- /dev/null +++ b/test/functional/lua/loop_spec.lua @@ -0,0 +1,55 @@ +-- Test suite for testing interactions with API bindings +local helpers = require('test.functional.helpers')(after_each) +local funcs = helpers.funcs +local meths = helpers.meths +local clear = helpers.clear +local sleep = helpers.sleep +local eq = helpers.eq +local matches = helpers.matches + +before_each(clear) + +describe('vim.loop', function() + + it('version', function() + assert(funcs.luaeval('vim.loop.version()')>=72961, "libuv version too old") + matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.loop.version_string()')) + end) + + it('timer', function() + meths.execute_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {}) + + local code=[[ + local loop = vim.loop + + local touch = 0 + local function wait(ms) + local this = coroutine.running() + assert(this) + local timer = loop.new_timer() + timer:start(ms, 0, 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) + coroutine.yield() + touch = touch + 1 + return touch + end + coroutine.wrap(function() + local touched = wait(10) + assert(touched==touch) + vim.api.nvim_set_var("coroutine_cnt", touched) + end)() + ]] + + eq(0, meths.get_var('coroutine_cnt')) + meths.execute_lua(code, {}) + sleep(20) + eq(2, meths.get_var('coroutine_cnt')) + eq(3, meths.get_var('coroutine_cnt_1')) + end) +end) diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index db4dae4b39..21a1752054 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -154,8 +154,11 @@ set(LIBTERMKEY_SHA256 cecbf737f35d18f433c8d7864f63c0f878af41f8bd0255a3ebb16010dc set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/b45b648cab73f9667bde7c0c6045b285e22b3ecd.tar.gz) set(LIBVTERM_SHA256 37cc123deff29327efa654358c2ebaaf8589da03754ca5adb8ec47be386a0433) -set(LUV_URL https://github.com/luvit/luv/archive/1.9.1-1.tar.gz) -set(LUV_SHA256 562b9efaad30aa051a40eac9ade0c3df48bb8186763769abe47ec3fb3edb1268) +set(LUV_URL https://github.com/luvit/luv/archive/1.29.1-2.tar.gz) +set(LUV_SHA256 e75d8fd2a14433bb798900a71e45318b3c0b8c2ef2c1c43593482ce95b4999e2) + +set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.7.tar.gz) +set(LUA_COMPAT53_SHA256 bec3a23114a3d9b3218038309657f0f506ad10dfbc03bb54e91da7e5ffdba0a2) set(GPERF_URL https://github.com/neovim/deps/raw/ff5b4b18a87397a8564016071ae64f64bcd8c635/opt/gperf-3.1.tar.gz) set(GPERF_SHA256 588546b945bba4b70b6a3a616e80b4ab466e3f33024a352fc2198112cdbb3ae2) diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index de4db35bfd..3ef7c6300e 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -182,7 +182,7 @@ if(USE_BUNDLED_BUSTED) add_custom_target(luacheck DEPENDS ${LUACHECK_EXE}) - set(LUV_DEPS luacheck luv-static) + set(LUV_DEPS luacheck luv-static lua-compat-5.3) if(MINGW AND CMAKE_CROSSCOMPILING) set(LUV_DEPS ${LUV_DEPS} libuv_host) endif() @@ -191,9 +191,10 @@ if(USE_BUNDLED_BUSTED) list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR}) endif() # DEPENDS on the previous module, because Luarocks breaks if parallel. + SET(LUV_PRIVATE_ARGS LUA_COMPAT53_INCDIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3) add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv COMMAND ${LUAROCKS_BINARY} - ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS} + ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS} ${LUV_PRIVATE_ARGS} WORKING_DIRECTORY ${DEPS_BUILD_DIR}/src/luv DEPENDS ${LUV_DEPS}) add_custom_target(luv diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake index a62ee72f91..5de5ddbf9c 100644 --- a/third-party/cmake/BuildLuv.cmake +++ b/third-party/cmake/BuildLuv.cmake @@ -15,8 +15,26 @@ function(BuildLuv) message(FATAL_ERROR "Must pass at least one of CONFIGURE_COMMAND, BUILD_COMMAND, INSTALL_COMMAND") endif() + ExternalProject_Add(lua-compat-5.3 + PREFIX ${DEPS_BUILD_DIR} + URL ${LUA_COMPAT53_URL} + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua-compat-5.3 + DOWNLOAD_COMMAND ${CMAKE_COMMAND} + -DPREFIX=${DEPS_BUILD_DIR} + -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/lua-compat-5.3 + -DURL=${LUA_COMPAT53_URL} + -DEXPECTED_SHA256=${LUA_COMPAT53_SHA256} + -DTARGET=lua-compat-5.3 + -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake + PATCH_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "") + ExternalProject_Add(luv-static PREFIX ${DEPS_BUILD_DIR} + DEPENDS lua-compat-5.3 URL ${LUV_URL} DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/luv DOWNLOAD_COMMAND ${CMAKE_COMMAND} @@ -94,9 +112,12 @@ endif() if(CMAKE_GENERATOR MATCHES "Unix Makefiles" AND (CMAKE_SYSTEM_NAME MATCHES ".*BSD" OR CMAKE_SYSTEM_NAME MATCHES "DragonFly")) - set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} "-DCMAKE_MAKE_PROGRAM=gmake" --build .) + set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} + "-DLUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3" + "-DCMAKE_MAKE_PROGRAM=gmake" --build .) else() - set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} --build .) + set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} + "-DLUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3" --build .) endif() set(LUV_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install)