From 97704cf48a22c5ec6c5e19ffab6acf2c8ca8af4a Mon Sep 17 00:00:00 2001 From: Folke Lemaitre Date: Mon, 24 Jun 2024 14:16:00 +0200 Subject: [PATCH] feat(build): build files and functions are now async. use coroutine.yield to interrupt and report progress --- lua/lazy/core/config.lua | 6 --- lua/lazy/manage/task/init.lua | 26 +++++++++ lua/lazy/manage/task/plugin.lua | 96 ++++++++++++++++++++++----------- lua/lazy/util.lua | 12 +++++ 4 files changed, 102 insertions(+), 38 deletions(-) diff --git a/lua/lazy/core/config.lua b/lua/lazy/core/config.lua index 624ce35..0919cab 100644 --- a/lua/lazy/core/config.lua +++ b/lua/lazy/core/config.lua @@ -183,12 +183,6 @@ M.defaults = { skip_if_doc_exists = true, }, state = vim.fn.stdpath("state") .. "/lazy/state.json", -- state info for checker and other things - build = { - -- Plugins can provide a `build.lua` file that will be executed when the plugin is installed - -- or updated. When the plugin spec also has a `build` command, the plugin's `build.lua` not be - -- executed. In this case, a warning message will be shown. - warn_on_override = true, - }, -- Enable profiling of lazy.nvim. This will add some overhead, -- so only enable this when you are debugging lazy.nvim profiling = { diff --git a/lua/lazy/manage/task/init.lua b/lua/lazy/manage/task/init.lua index 2397cdf..d86ef5f 100644 --- a/lua/lazy/manage/task/init.lua +++ b/lua/lazy/manage/task/init.lua @@ -74,6 +74,32 @@ function Task:start() self:_check() end +---@param fn async fun() +function Task:async(fn) + local co = coroutine.create(fn) + local check = vim.uv.new_check() + check:start(vim.schedule_wrap(function() + local status = coroutine.status(co) + if status == "dead" then + check:stop() + self:_check() + elseif status == "suspended" then + local ok, res = coroutine.resume(co) + if not ok then + error(res) + elseif res then + self.status = res + self.output = self.output .. "\n" .. res + vim.api.nvim_exec_autocmds("User", { pattern = "LazyRender", modeline = false }) + end + end + end)) + + table.insert(self._running, function() + return check:is_active() + end) +end + ---@private function Task:_check() for _, state in ipairs(self._running) do diff --git a/lua/lazy/manage/task/plugin.lua b/lua/lazy/manage/task/plugin.lua index e058c50..cd01a25 100644 --- a/lua/lazy/manage/task/plugin.lua +++ b/lua/lazy/manage/task/plugin.lua @@ -8,25 +8,67 @@ local M = {} ---@param plugin LazyPlugin local function get_build_file(plugin) for _, path in ipairs({ "build.lua", "build/init.lua" }) do - path = plugin.dir .. "/" .. path - if Util.file_exists(path) then + if Util.file_exists(plugin.dir .. "/" .. path) then return path end end end +local B = {} + +---@param task LazyTask +function B.rockspec(task) + local root = Config.options.rocks.root .. "/" .. task.plugin.name + vim.fn.mkdir(root, "p") + task:spawn("luarocks", { + args = { + "--tree", + root, + "--server", + Config.options.rocks.server, + "--dev", + "--lua-version", + "5.1", + "make", + "--force-fast", + }, + cwd = task.plugin.dir, + }) +end + +---@param task LazyTask +---@param build string +function B.cmd(task, build) + local cmd = vim.api.nvim_parse_cmd(build:sub(2), {}) --[[@as vim.api.keyset.cmd]] + task.output = vim.api.nvim_cmd(cmd, { output = true }) +end + +---@param task LazyTask +---@param build string +function B.shell(task, build) + local shell = vim.env.SHELL or vim.o.shell + local shell_args = shell:find("cmd.exe", 1, true) and "/c" or "-c" + + task:spawn(shell, { + args = { shell_args, build }, + cwd = task.plugin.dir, + }) +end + M.build = { ---@param opts? {force:boolean} skip = function(plugin, opts) if opts and opts.force then return false end - return not (plugin._.dirty and (plugin.build or get_build_file(plugin))) + return not ((plugin._.dirty or plugin._.build) and (plugin.build or get_build_file(plugin))) end, run = function(self) vim.cmd([[silent! runtime plugin/rplugin.vim]]) - Loader.load(self.plugin, { task = "build" }) + if self.plugin.build ~= "rockspec" then + Loader.load(self.plugin, { task = "build" }) + end local builders = self.plugin.build @@ -35,39 +77,29 @@ M.build = { return end - local build_file = get_build_file(self.plugin) - if build_file then - if builders then - if Config.options.build.warn_on_override then - Util.warn( - ("Plugin **%s** provides its own build script, but you also defined a `build` command.\nThe `build.lua` file will not be used"):format( - self.plugin.name - ) - ) - end - else - builders = function() - Loader.source(build_file) - end - end - end + builders = builders or get_build_file(self.plugin) + if builders then builders = type(builders) == "table" and builders or { builders } ---@cast builders (string|fun(LazyPlugin))[] for _, build in ipairs(builders) do - if type(build) == "string" and build:sub(1, 1) == ":" then - local cmd = vim.api.nvim_parse_cmd(build:sub(2), {}) - self.output = vim.api.nvim_cmd(cmd, { output = true }) - elseif type(build) == "function" then - build(self.plugin) + if type(build) == "function" then + self:async(function() + build(self.plugin) + end) + elseif build == "rockspec" then + B.rockspec(self) + elseif build:sub(1, 1) == ":" then + B.cmd(self, build) + elseif build:match("%.lua$") then + local file = self.plugin.dir .. "/" .. build + local chunk, err = loadfile(file) + if not chunk or err then + error(err) + end + self:async(chunk) else - local shell = vim.env.SHELL or vim.o.shell - local shell_args = shell:find("cmd.exe", 1, true) and "/c" or "-c" - - self:spawn(shell, { - args = { shell_args, build }, - cwd = self.plugin.dir, - }) + B.shell(self, build) end end end diff --git a/lua/lazy/util.lua b/lua/lazy/util.lua index 755c1cd..813b4d9 100644 --- a/lua/lazy/util.lua +++ b/lua/lazy/util.lua @@ -231,6 +231,18 @@ function M.markdown(msg, opts) ) end +---@async +---@param ms number +function M.sleep(ms) + local continue = false + vim.defer_fn(function() + continue = true + end, ms) + while not continue do + coroutine.yield() + end +end + function M._dump(value, result) local t = type(value) if t == "number" or t == "boolean" then