From 2381f507189e3e10a43c3932a3ec6c2847180abc Mon Sep 17 00:00:00 2001 From: William Boman Date: Mon, 5 Dec 2022 17:48:34 +0100 Subject: fix(package): don't call vim API functions inside fast event (#730) --- lua/mason-core/package/init.lua | 10 ++-- lua/mason-core/terminator.lua | 104 +++++++++++++++++++++++++++++++++++++++ lua/mason/init.lua | 11 +---- lua/mason/terminator.lua | 106 ---------------------------------------- 4 files changed, 109 insertions(+), 122 deletions(-) create mode 100644 lua/mason-core/terminator.lua delete mode 100644 lua/mason/terminator.lua (limited to 'lua') diff --git a/lua/mason-core/package/init.lua b/lua/mason-core/package/init.lua index e46219b7..faf25764 100644 --- a/lua/mason-core/package/init.lua +++ b/lua/mason-core/package/init.lua @@ -81,12 +81,10 @@ function Package:new_handle() local handle = InstallationHandle.new(self) self.handle = handle - -- First emit a private autocmd via the native event bus. This is to enable some internal perf improvements (helps avoid loading some Lua modules). - if vim.fn.has "nvim-0.8.0" == 1 then - vim.api.nvim_exec_autocmds("User", { pattern = "__MasonPackageHandle", data = self.name }) - else - vim.api.nvim_exec_autocmds("User", { pattern = "__MasonPackageHandle" }) - end + -- Ideally we'd decouple this and leverage Mason's event system, but to allow loading as little as possible during + -- setup (i.e. not load modules related to Mason's event system) of the mason.nvim plugin we explicitly call into + -- terminator here. + require("mason-core.terminator").register(handle) self:emit("handle", handle) registry:emit("package:handle", self, handle) diff --git a/lua/mason-core/terminator.lua b/lua/mason-core/terminator.lua new file mode 100644 index 00000000..b7acefe8 --- /dev/null +++ b/lua/mason-core/terminator.lua @@ -0,0 +1,104 @@ +local a = require "mason-core.async" + +-- Hasta la vista, baby. +-- ______ +-- <((((((\\\ +-- / . }\ +-- ;--..--._|} +-- (\ '--/\--' ) +-- \\ | '-' :'| +-- \\ . -==- .-| +-- \\ \.__.' \--._ +-- [\\ __.--| // _/'--. +-- \ \\ .'-._ ('-----'/ __/ \ +-- \ \\ / __>| | '--. | +-- \ \\ | \ | / / / +-- \ '\ / \ | | _/ / +-- \ \ \ | | / / +-- snd \ \ \ / + +local M = {} + +---@async +---@param handles InstallHandle[] +---@param grace_ms integer +local function terminate_handles(handles, grace_ms) + a.wait_all(vim.tbl_map( + ---@param handle InstallHandle + function(handle) + return function() + a.wait_first { + function() + if not handle:is_closed() then + handle:terminate() + end + a.wait(function(resolve) + if handle:is_closed() then + resolve() + else + handle:once("closed", resolve) + end + end) + end, + function() + a.sleep(grace_ms) + if not handle:is_closed() then + handle:kill(9) -- SIGKILL + end + end, + } + end + end, + handles + )) +end + +local active_handles = {} + +---@parma handle InstallHandle +function M.register(handle) + if handle:is_closed() then + return + end + active_handles[handle] = true + handle:once("closed", function() + active_handles[handle] = nil + end) +end + +---@param grace_ms integer +function M.terminate(grace_ms) + local handles = vim.tbl_keys(active_handles) + if #handles > 0 then + local package_names = vim.tbl_map(function(h) + return h.package.name + end, handles) + table.sort(package_names) + + -- 1. Print warning message. + vim.api.nvim_echo({ + { + "[mason.nvim] Neovim is exiting while packages are still installing. Terminating all installations…", + "WarningMsg", + }, + }, true, {}) + vim.cmd "redraw" + + -- 2. Synchronously terminate all installation handles. + a.run_blocking(function() + terminate_handles(handles, grace_ms) + end) + + -- 3. Schedule error message to be displayed so that Neovim prints it to the tty. + -- XXX: does this need to be conditional on which UIs are attached? + vim.schedule(function() + vim.api.nvim_err_writeln( + ("[mason.nvim] Neovim exited while the following packages were installing. Installation was aborted.\n- %s"):format( + table.concat(package_names, #package_names > 5 and ", " or "\n- ") + ) + ) + end) + end +end + +return M diff --git a/lua/mason/init.lua b/lua/mason/init.lua index 62a66bea..6bbb411a 100644 --- a/lua/mason/init.lua +++ b/lua/mason/init.lua @@ -5,18 +5,9 @@ local platform = require "mason-core.platform" local M = {} local function setup_autocmds() - -- lazily set up terminator - vim.api.nvim_create_autocmd("User", { - pattern = "__MasonPackageHandle", -- private autocmd specific for this very use case - callback = function() - require("mason.terminator").setup() - end, - once = true, - }) - vim.api.nvim_create_autocmd("VimLeavePre", { callback = function() - require("mason.terminator").terminate(5000) + require("mason-core.terminator").terminate(5000) end, once = true, }) diff --git a/lua/mason/terminator.lua b/lua/mason/terminator.lua deleted file mode 100644 index ea4bd5a2..00000000 --- a/lua/mason/terminator.lua +++ /dev/null @@ -1,106 +0,0 @@ -local registry = require "mason-registry" -local a = require "mason-core.async" - --- Hasta la vista, baby. --- ______ --- <((((((\\\ --- / . }\ --- ;--..--._|} --- (\ '--/\--' ) --- \\ | '-' :'| --- \\ . -==- .-| --- \\ \.__.' \--._ --- [\\ __.--| // _/'--. --- \ \\ .'-._ ('-----'/ __/ \ --- \ \\ / __>| | '--. | --- \ \\ | \ | / / / --- \ '\ / \ | | _/ / --- \ \ \ | | / / --- snd \ \ \ / - -local M = {} - ----@async ----@param handles InstallHandle[] ----@param grace_ms integer -local function terminate_handles(handles, grace_ms) - a.wait_all(vim.tbl_map( - ---@param handle InstallHandle - function(handle) - return function() - a.wait_first { - function() - if not handle:is_closed() then - handle:terminate() - end - a.wait(function(resolve) - if handle:is_closed() then - resolve() - else - handle:once("closed", resolve) - end - end) - end, - function() - a.sleep(grace_ms) - if not handle:is_closed() then - handle:kill(9) -- SIGKILL - end - end, - } - end - end, - handles - )) -end - -local active_handles = {} - -function M.setup() - registry:on("package:handle", function(_, handle) - if handle:is_closed() then - return - end - active_handles[handle] = true - handle:once("closed", function() - active_handles[handle] = nil - end) - end) -end - ----@param grace_ms integer -function M.terminate(grace_ms) - local handles = vim.tbl_keys(active_handles) - if #handles > 0 then - local package_names = vim.tbl_map(function(h) - return h.package.name - end, handles) - table.sort(package_names) - - -- 1. Print warning message. - vim.api.nvim_echo({ - { - "[mason.nvim] Neovim is exiting while packages are still installing. Terminating all installations…", - "WarningMsg", - }, - }, true, {}) - vim.cmd "redraw" - - -- 2. Synchronously terminate all installation handles. - a.run_blocking(function() - terminate_handles(handles, grace_ms) - end) - - -- 3. Schedule error message to be displayed so that Neovim prints it to the tty. - -- XXX: does this need to be conditional on which UIs are attached? - vim.schedule(function() - vim.api.nvim_err_writeln( - ("[mason.nvim] Neovim exited while the following packages were installing. Installation was aborted.\n- %s"):format( - table.concat(package_names, #package_names > 5 and ", " or "\n- ") - ) - ) - end) - end -end - -return M -- cgit v1.2.3-70-g09d2