diff options
| -rw-r--r-- | doc/mason.txt | 4 | ||||
| -rw-r--r-- | lua/mason-core/package/init.lua | 2 | ||||
| -rw-r--r-- | lua/mason/api/command.lua | 79 |
3 files changed, 78 insertions, 7 deletions
diff --git a/doc/mason.txt b/doc/mason.txt index 6d6ecbd9..9ae43be1 100644 --- a/doc/mason.txt +++ b/doc/mason.txt @@ -75,6 +75,10 @@ Opens the graphical status window. :MasonInstall <package> ... Installs the provided packages. +Runs in blocking fashion if there are no UIs attached (i.e. running in +headless mode), example: + + $ nvim --headless -c "MasonInstall stylua" -c "qall" *:MasonUninstall* :MasonUninstall <package> ... diff --git a/lua/mason-core/package/init.lua b/lua/mason-core/package/init.lua index 631e423d..ec4bf8f1 100644 --- a/lua/mason-core/package/init.lua +++ b/lua/mason-core/package/init.lua @@ -138,7 +138,7 @@ function Package:uninstall() end function Package:unlink() - log.fmt_info("Unlinking %s", self) + log.fmt_trace("Unlinking %s", self) local install_path = self:get_install_path() -- 1. Unlink self:get_receipt():map(_.prop "links"):if_present(function(links) diff --git a/lua/mason/api/command.lua b/lua/mason/api/command.lua index 064477f4..084f148f 100644 --- a/lua/mason/api/command.lua +++ b/lua/mason/api/command.lua @@ -24,16 +24,83 @@ local filter_valid_packages = _.filter(function(pkg_specifier) end end) +---@param handles InstallHandle[] +local function join_handles(handles) + local a = require "mason-core.async" + local Optional = require "mason-core.optional" + + _.each( + ---@param handle InstallHandle + function(handle) + handle:on("stdout", vim.schedule_wrap(vim.api.nvim_out_write)) + handle:on("stderr", vim.schedule_wrap(vim.api.nvim_err_write)) + end, + handles + ) + + a.run_blocking(function() + a.wait_all(_.map( + ---@param handle InstallHandle + function(handle) + return function() + a.wait(function(resolve) + if handle:is_closed() then + resolve() + else + handle:once("closed", resolve) + end + end) + end + end, + handles + )) + local failed_packages = _.filter_map(function(handle) + -- TODO: The outcome of a package installation is currently not captured in the handle, but is instead + -- internalized in the Package instance itself. Change this to assert on the handle state when it's + -- available. + if not handle.package:is_installed() then + return Optional.of(handle.package.name) + else + return Optional.empty() + end + end, handles) + + if _.length(failed_packages) > 0 then + a.scheduler() -- wait for scheduler for logs to finalize + a.scheduler() -- logs have been written + vim.api.nvim_err_writeln "" + vim.api.nvim_err_writeln( + ("The following packages failed to install: %s"):format(_.join(", ", failed_packages)) + ) + vim.cmd [[1cq]] + end + end) +end + vim.api.nvim_create_user_command("MasonInstall", function(opts) local Package = require "mason-core.package" local registry = require "mason-registry" local valid_packages = filter_valid_packages(opts.fargs) - if #valid_packages > 0 then - _.each(function(pkg_specifier) - local package_name, version = Package.Parse(pkg_specifier) - local pkg = registry.get_package(package_name) - pkg:install { version = version } - end, valid_packages) + local is_headless = #vim.api.nvim_list_uis() == 0 + + if is_headless and #valid_packages ~= #opts.fargs then + -- When executing in headless mode we don't allow any of the provided packages to be invalid. + -- This is to avoid things like scripts silently not erroring even if they've provided one or more invalid packages. + return vim.cmd [[1cq]] + elseif #valid_packages == 0 then + return + end + + ---@type InstallHandle[] + local handles = _.map(function(pkg_specifier) + local package_name, version = Package.Parse(pkg_specifier) + local pkg = registry.get_package(package_name) + return pkg:install { version = version } + end, valid_packages) + + if is_headless then + join_handles(handles) + else require("mason.ui").open() end end, { |
