diff options
| -rw-r--r-- | lua/mason-core/managers/npm/init.lua | 1 | ||||
| -rw-r--r-- | lua/mason/ui/components/main/package_list.lua | 86 | ||||
| -rw-r--r-- | lua/mason/ui/instance.lua | 77 |
3 files changed, 90 insertions, 74 deletions
diff --git a/lua/mason-core/managers/npm/init.lua b/lua/mason-core/managers/npm/init.lua index 96571420..7bfa74b4 100644 --- a/lua/mason-core/managers/npm/init.lua +++ b/lua/mason-core/managers/npm/init.lua @@ -20,6 +20,7 @@ local function ensure_npm_root(ctx) if not (ctx.fs:dir_exists "node_modules" or ctx.fs:file_exists "package.json") then -- Create a package.json to set a boundary for where npm installs packages. ctx.spawn.npm { "init", "--yes", "--scope=mason" } + ctx.stdio_sink.stdout "Initialized npm root\n" end end diff --git a/lua/mason/ui/components/main/package_list.lua b/lua/mason/ui/components/main/package_list.lua index 5b4600cf..870fe890 100644 --- a/lua/mason/ui/components/main/package_list.lua +++ b/lua/mason/ui/components/main/package_list.lua @@ -5,13 +5,13 @@ local settings = require "mason.settings" local JsonSchema = require "mason.ui.components.json-schema" ----@param props { state: InstallerUiState, heading: INode, packages: Package[], list_item_renderer: (fun(package: Package): INode), hide_when_empty: boolean } +---@param props { state: InstallerUiState, heading: INode, packages: Package[], list_item_renderer: (fun(package: Package, state: InstallerUiState): INode), hide_when_empty: boolean } local function PackageListContainer(props) local items = {} for i = 1, #props.packages do local pkg = props.packages[i] if props.state.packages.visible[pkg.name] then - items[#items + 1] = props.list_item_renderer(pkg) + items[#items + 1] = props.list_item_renderer(pkg, props.state) end end @@ -189,6 +189,42 @@ local function Installed(state) } end +---@param pkg Package +---@param state InstallerUiState +local function InstallingPackageComponent(pkg, state) + ---@type UiPackageState + local pkg_state = state.packages.states[pkg.name] + local current_state = pkg_state.is_terminated and p.Comment " (cancelling)" or p.none "" + local tail = pkg_state.short_tailed_output + and ("▶ (#" .. #pkg_state.tailed_output .. ") " .. pkg_state.short_tailed_output) + or "" + return Ui.Node { + Ui.HlTextNode { + { + pkg_state.has_failed and p.error(settings.current.ui.icons.package_uninstalled) + or p.highlight(settings.current.ui.icons.package_pending), + p.none(" " .. pkg.name), + current_state, + pkg_state.latest_spawn and p.Comment((" $ %s"):format(pkg_state.latest_spawn)) or p.none "", + }, + }, + Ui.StickyCursor { id = ("%s-installing"):format(pkg.spec.name) }, + Ui.Keybind(settings.current.ui.keymaps.cancel_installation, "TERMINATE_PACKAGE_HANDLE", pkg), + Ui.Keybind(settings.current.ui.keymaps.install_package, "INSTALL_PACKAGE", pkg), + Ui.CascadingStyleNode({ "INDENT" }, { + Ui.HlTextNode(pkg_state.is_log_expanded and p.Bold "▼ Displaying full log" or p.muted(tail)), + Ui.Keybind("<CR>", "TOGGLE_INSTALL_LOG", pkg), + }), + Ui.When(pkg_state.is_log_expanded, function() + return Ui.CascadingStyleNode({ "INDENT", "INDENT" }, { + Ui.HlTextNode(_.map(function(line) + return { p.muted(line) } + end, pkg_state.tailed_output)), + }) + end), + } +end + ---@param state InstallerUiState local function Installing(state) local packages = state.packages.installing @@ -202,28 +238,7 @@ local function Installing(state) hide_when_empty = true, packages = packages, ---@param pkg Package - list_item_renderer = function(pkg) - ---@type UiPackageState - local pkg_state = state.packages.states[pkg.name] - local current_state = pkg_state.is_terminated and p.Comment " (cancelling)" or p.none "" - return Ui.Node { - Ui.HlTextNode { - { - p.highlight(settings.current.ui.icons.package_pending), - p.none(" " .. pkg.name), - current_state, - pkg_state.latest_spawn and p.Comment((" $ %s"):format(pkg_state.latest_spawn)) or p.none "", - }, - }, - Ui.StickyCursor { id = ("%s-installing"):format(pkg.spec.name) }, - Ui.Keybind(settings.current.ui.keymaps.cancel_installation, "TERMINATE_PACKAGE_HANDLE", pkg), - Ui.CascadingStyleNode({ "INDENT" }, { - Ui.HlTextNode(_.map(function(line) - return { p.muted(line) } - end, pkg_state.short_tailed_output)), - }), - } - end, + list_item_renderer = InstallingPackageComponent, } end @@ -263,24 +278,7 @@ local function Failed(state) heading = Ui.HlTextNode(p.heading "Failed"), packages = packages, ---@param pkg Package - list_item_renderer = function(pkg) - ---@type UiPackageState - local pkg_state = state.packages.states[pkg.name] - return Ui.Node { - PackageComponent(state, pkg, { - icon = p.error(settings.current.ui.icons.package_pending), - keybinds = { - Ui.Keybind(settings.current.ui.keymaps.install_package, "INSTALL_PACKAGE", pkg), - }, - sticky = Ui.StickyCursor { id = ("%s-installing"):format(pkg.name) }, - }), - Ui.CascadingStyleNode({ "INDENT" }, { - Ui.HlTextNode(_.map(function(line) - return { p.muted(line) } - end, pkg_state.tailed_output)), - }), - } - end, + list_item_renderer = InstallingPackageComponent, } end @@ -307,10 +305,10 @@ end ---@param state InstallerUiState return function(state) return Ui.CascadingStyleNode({ "INDENT" }, { - Installed(state), + Failed(state), Installing(state), Queued(state), - Failed(state), + Installed(state), Uninstalled(state), }) end diff --git a/lua/mason/ui/instance.lua b/lua/mason/ui/instance.lua index 4b2f43e4..c7000bc5 100644 --- a/lua/mason/ui/instance.lua +++ b/lua/mason/ui/instance.lua @@ -45,11 +45,13 @@ end ---@field is_checking_new_version boolean ---@field is_checking_version boolean ---@field is_terminated boolean +---@field is_log_expanded boolean +---@field has_failed boolean ---@field latest_spawn string? ---@field linked_executables table<string, string>? ---@field lsp_settings_schema table? ---@field new_version NewPackageVersion? ----@field short_tailed_output string[] +---@field short_tailed_output string? ---@field tailed_output string[] ---@field version string? @@ -179,6 +181,28 @@ local function mutate_package_visibility(mutate_fn) end) end +---@return UiPackageState +local function create_initial_package_state() + return { + expanded_json_schema_keys = {}, + expanded_json_schemas = {}, + has_expanded_before = false, + has_transitioned = false, + is_checking_new_version = false, + is_checking_version = false, + is_terminated = false, + is_log_expanded = false, + has_failed = false, + latest_spawn = nil, + linked_executables = nil, + lsp_settings_schema = nil, + new_version = nil, + short_tailed_output = nil, + tailed_output = {}, + version = nil, + } +end + ---@param handle InstallHandle local function setup_handle(handle) local function handle_state_change() @@ -199,20 +223,20 @@ local function setup_handle(handle) ---@param chunk string local function handle_output(chunk) mutate_state(function(state) - -- TODO: improve this local pkg_state = state.packages.states[handle.package.name] - for idx, line in ipairs(vim.split(chunk, "\n")) do - if idx == 1 and pkg_state.tailed_output[#pkg_state.tailed_output] then + local lines = vim.split(chunk, "\n") + for i = 1, #lines do + local line = lines[i] + if i == 1 and pkg_state.tailed_output[#pkg_state.tailed_output] then pkg_state.tailed_output[#pkg_state.tailed_output] = pkg_state.tailed_output[#pkg_state.tailed_output] .. line else pkg_state.tailed_output[#pkg_state.tailed_output + 1] = line end + if not line:match "^%s*$" then + pkg_state.short_tailed_output = line:gsub("^%s+", "") + end end - pkg_state.short_tailed_output = { - pkg_state.tailed_output[#pkg_state.tailed_output - 1] or "", - pkg_state.tailed_output[#pkg_state.tailed_output] or "", - } end) end @@ -239,7 +263,8 @@ local function setup_handle(handle) handle_state_change() handle_spawnhandle_change() mutate_state(function(state) - state.packages.states[handle.package.name].tailed_output = {} + state.packages.states[handle.package.name] = create_initial_package_state() + state.packages.states[handle.package.name].short_tailed_output = "Installing…" end) end @@ -272,26 +297,6 @@ local function hydrate_detailed_package_state(pkg) ) end ----@return UiPackageState -local function create_initial_package_state() - return { - expanded_json_schema_keys = {}, - expanded_json_schemas = {}, - has_expanded_before = false, - has_transitioned = false, - is_checking_new_version = false, - is_checking_version = false, - is_terminated = false, - latest_spawn = nil, - linked_executables = nil, - lsp_settings_schema = nil, - new_version = nil, - short_tailed_output = {}, - tailed_output = {}, - version = nil, - } -end - local help_animation do local help_command = ":help" @@ -543,6 +548,14 @@ local function update_all_packages() ) end +local function toggle_install_log(event) + ---@type Package + local pkg = event.payload + mutate_state(function(state) + state.packages.states[pkg.name].is_log_expanded = not state.packages.states[pkg.name].is_log_expanded + end) +end + local effects = { ["CHECK_NEW_PACKAGE_VERSION"] = a.scope(_.compose(_.partial(pcall, check_new_package_version), _.prop "payload")), ["CHECK_NEW_VISIBLE_PACKAGE_VERSIONS"] = a.scope(check_new_visible_package_versions), @@ -551,11 +564,12 @@ local effects = { ["INSTALL_PACKAGE"] = install_package, ["LANGUAGE_FILTER"] = filter, ["SET_VIEW"] = set_view, - ["TERMINATE_PACKAGE_HANDLES"] = terminate_all_package_handles, ["TERMINATE_PACKAGE_HANDLE"] = terminate_package_handle, + ["TERMINATE_PACKAGE_HANDLES"] = terminate_all_package_handles, ["TOGGLE_EXPAND_CURRENT_SETTINGS"] = toggle_expand_current_settings, ["TOGGLE_EXPAND_PACKAGE"] = toggle_expand_package, ["TOGGLE_HELP"] = toggle_help, + ["TOGGLE_INSTALL_LOG"] = toggle_install_log, ["TOGGLE_JSON_SCHEMA"] = toggle_json_schema, ["TOGGLE_JSON_SCHEMA_KEY"] = toggle_json_schema_keys, ["UNINSTALL_PACKAGE"] = uninstall_package, @@ -596,6 +610,9 @@ for _, pkg in ipairs(packages) do mutate_package_grouping(pkg, pkg:is_installed() and "installed" or "uninstalled") else mutate_package_grouping(pkg, "failed") + mutate_state(function(state) + state.packages.states[pkg.name].has_failed = true + end) end end ) |
