diff options
| author | William Boman <william@redwill.se> | 2022-05-11 16:10:57 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-11 16:10:57 +0200 |
| commit | 5e3385d90668c792919c7e2791620a6c0d569538 (patch) | |
| tree | 4b0158d3ac7765db47411d57ec754a96f8eaf1f9 /lua/nvim-lsp-installer/ui/status-win/init.lua | |
| parent | chore!: remove zeta_note (diff) | |
| download | mason-5e3385d90668c792919c7e2791620a6c0d569538.tar mason-5e3385d90668c792919c7e2791620a6c0d569538.tar.gz mason-5e3385d90668c792919c7e2791620a6c0d569538.tar.bz2 mason-5e3385d90668c792919c7e2791620a6c0d569538.tar.lz mason-5e3385d90668c792919c7e2791620a6c0d569538.tar.xz mason-5e3385d90668c792919c7e2791620a6c0d569538.tar.zst mason-5e3385d90668c792919c7e2791620a6c0d569538.zip | |
chore: further decouple module structure (#685)
Diffstat (limited to 'lua/nvim-lsp-installer/ui/status-win/init.lua')
| -rw-r--r-- | lua/nvim-lsp-installer/ui/status-win/init.lua | 1056 |
1 files changed, 0 insertions, 1056 deletions
diff --git a/lua/nvim-lsp-installer/ui/status-win/init.lua b/lua/nvim-lsp-installer/ui/status-win/init.lua deleted file mode 100644 index 689e3710..00000000 --- a/lua/nvim-lsp-installer/ui/status-win/init.lua +++ /dev/null @@ -1,1056 +0,0 @@ -local a = require "nvim-lsp-installer.core.async" -local Ui = require "nvim-lsp-installer.ui" -local fs = require "nvim-lsp-installer.fs" -local log = require "nvim-lsp-installer.log" -local Data = require "nvim-lsp-installer.data" -local display = require "nvim-lsp-installer.ui.display" -local settings = require "nvim-lsp-installer.settings" -local lsp_servers = require "nvim-lsp-installer.servers" -local JobExecutionPool = require "nvim-lsp-installer.jobs.pool" -local outdated_servers = require "nvim-lsp-installer.jobs.outdated-servers" -local version_check = require "nvim-lsp-installer.jobs.version-check" -local ServerHints = require "nvim-lsp-installer.ui.status-win.server_hints" -local ServerSettingsSchema = require "nvim-lsp-installer.ui.status-win.components.settings-schema" - -local HELP_KEYMAP = "?" -local CLOSE_WINDOW_KEYMAP_1 = "<Esc>" -local CLOSE_WINDOW_KEYMAP_2 = "q" - ----@param props {title: string, subtitle: string[][], count: number} -local function ServerGroupHeading(props) - local line = { - { props.title, props.highlight or "LspInstallerHeading" }, - { " (" .. props.count .. ") ", "Comment" }, - } - if props.subtitle then - vim.list_extend(line, props.subtitle) - end - return Ui.HlTextNode { line } -end - -local function Indent(children) - return Ui.CascadingStyleNode({ "INDENT" }, children) -end - -local create_vader = Data.memoize( - ---@param saber_ticks number - function(saber_ticks) - -- stylua: ignore start - return { - { { [[ _________________________________________________________________________________________ ]], "LspInstallerMuted" } }, - { { [[ < Help sponsor nvim-lsp-installer development! ]], "LspInstallerMuted" }, { "https://github.com/sponsors/williamboman", "LspInstallerHighlighted"}, {[[ > ]], "LspInstallerMuted" } }, - { { [[ < Help sponsor neovim development! ]], "LspInstallerMuted" }, { "https://github.com/sponsors/neovim", "LspInstallerHighlighted"}, {[[ > ]], "LspInstallerMuted" } }, - { { [[ ----------------------------------------------------------------------------------------- ]], "LspInstallerMuted" } }, - { { [[ ]], ""}, {[[\]], saber_ticks >= 3 and "LspInstallerVaderSaber" or "LspInstallerMuted"}, {[[ ,-^-. ]], "LspInstallerMuted" } }, - { { [[ ]], ""}, {[[\]], saber_ticks >= 2 and "LspInstallerVaderSaber" or "LspInstallerMuted"}, {[[ !oYo! ]], "LspInstallerMuted" } }, - { { [[ ]], ""}, {[[\]], saber_ticks >= 1 and "LspInstallerVaderSaber" or "LspInstallerMuted"}, {[[ /./=\.\______ ]], "LspInstallerMuted" } }, - { { [[ ## )\/\ ]], "LspInstallerMuted" } }, - { { [[ ||-----w|| ]], "LspInstallerMuted" } }, - { { [[ || || ]], "LspInstallerMuted" } }, - { { [[ ]], "LspInstallerMuted" } }, - { { [[ Cowth Vader (alleged Neovim user) ]], "LspInstallerMuted" } }, - { { [[ ]], "LspInstallerMuted" } }, - } - -- stylua: ignore end - end -) - ----@param is_current_settings_expanded boolean ----@param vader_saber_ticks number -local function Help(is_current_settings_expanded, vader_saber_ticks) - local keymap_tuples = { - { "Toggle help", HELP_KEYMAP }, - { "Toggle server info", settings.current.ui.keymaps.toggle_server_expand }, - { "Update server", settings.current.ui.keymaps.update_server }, - { "Update all installed servers", settings.current.ui.keymaps.update_all_servers }, - { "Check for new server version", settings.current.ui.keymaps.check_server_version }, - { "Check for new versions (all servers)", settings.current.ui.keymaps.check_outdated_servers }, - { "Uninstall server", settings.current.ui.keymaps.uninstall_server }, - { "Install server", settings.current.ui.keymaps.install_server }, - { "Close window", CLOSE_WINDOW_KEYMAP_1 }, - { "Close window", CLOSE_WINDOW_KEYMAP_2 }, - } - - local very_reasonable_cow = create_vader(vader_saber_ticks) - - return Ui.Node { - Ui.EmptyLine(), - Ui.HlTextNode { - { { "Installer log: ", "LspInstallerMuted" }, { log.outfile, "" } }, - }, - Ui.EmptyLine(), - Ui.Table(vim.list_extend( - { - { - { "Keyboard shortcuts", "LspInstallerLabel" }, - }, - }, - Data.list_map(function(keymap_tuple) - return { { keymap_tuple[1], "LspInstallerMuted" }, { keymap_tuple[2], "LspInstallerHighlighted" } } - end, keymap_tuples) - )), - Ui.EmptyLine(), - Ui.HlTextNode { - { { "Problems installing/uninstalling servers", "LspInstallerLabel" } }, - { - { - "Make sure you meet the minimum requirements to install servers. For debugging, refer to:", - "LspInstallerMuted", - }, - }, - }, - Indent { - Ui.HlTextNode { - { - { ":help nvim-lsp-installer-debugging", "LspInstallerHighlighted" }, - }, - { - { ":checkhealth nvim-lsp-installer", "LspInstallerHighlighted" }, - }, - }, - }, - Ui.EmptyLine(), - Ui.HlTextNode { - { { "Problems with server functionality", "LspInstallerLabel" } }, - { - { - "Please refer to each language server's own homepage for further assistance.", - "LspInstallerMuted", - }, - }, - }, - Ui.EmptyLine(), - Ui.HlTextNode { - { { "Missing a server?", "LspInstallerLabel" } }, - { - { - "Create an issue at ", - "LspInstallerMuted", - }, - { - "https://github.com/williamboman/nvim-lsp-installer/issues/new/choose", - "LspInstallerHighlighted", - }, - }, - }, - Ui.EmptyLine(), - Ui.HlTextNode { - { { "How do I customize server settings?", "LspInstallerLabel" } }, - { - { "For information on how to customize a server's settings, see ", "LspInstallerMuted" }, - { ":help lspconfig-setup", "LspInstallerHighlighted" }, - }, - }, - Ui.EmptyLine(), - Ui.HlTextNode { - { - { - ("%s Current settings"):format(is_current_settings_expanded and "↓" or "→"), - "LspInstallerLabel", - }, - { " :help nvim-lsp-installer-settings", "LspInstallerHighlighted" }, - }, - }, - Ui.Keybind("<CR>", "TOGGLE_EXPAND_CURRENT_SETTINGS", nil), - Ui.When(is_current_settings_expanded, function() - local settings_split_by_newline = vim.split(vim.inspect(settings.current), "\n") - local current_settings = Data.list_map(function(line) - return { { line, "LspInstallerMuted" } } - end, settings_split_by_newline) - return Ui.HlTextNode(current_settings) - end), - Ui.EmptyLine(), - Ui.HlTextNode(very_reasonable_cow), - } -end - ----@param props {is_showing_help: boolean, help_command_text: string} -local function Header(props) - return Ui.CascadingStyleNode({ "CENTERED" }, { - Ui.HlTextNode { - { - { props.is_showing_help and props.help_command_text or "", "LspInstallerHighlighted" }, - { - props.is_showing_help and "nvim-lsp-installer" .. (" "):rep(#props.help_command_text) - or "nvim-lsp-installer", - props.is_showing_help and "LspInstallerHighlighted" or "LspInstallerHeader", - }, - }, - { - { props.is_showing_help and " press " or "press ", "LspInstallerMuted" }, - { "?", props.is_showing_help and "LspInstallerOrange" or "LspInstallerHighlighted" }, - { props.is_showing_help and " for server list" or " for help", "LspInstallerMuted" }, - }, - { - { "https://github.com/williamboman/nvim-lsp-installer", "Comment" }, - }, - }, - }) -end - ----@param time number -local function format_time(time) - return os.date("%d %b %Y %H:%M", time) -end - ----@param outdated_packages OutdatedPackage[] ----@return string -local function format_new_package_versions(outdated_packages) - local result = {} - if #outdated_packages == 1 then - return outdated_packages[1].latest_version - end - for _, outdated_package in ipairs(outdated_packages) do - result[#result + 1] = ("%s@%s"):format(outdated_package.name, outdated_package.latest_version) - end - return table.concat(result, ", ") -end - ----@param server ServerState -local function ServerMetadata(server) - return Ui.Node(Data.list_not_nil( - Data.lazy_when(server.is_installed and server.deprecated, function() - return Ui.Node(Data.list_not_nil( - Ui.HlTextNode { server.deprecated.message, "Comment" }, - Data.lazy_when(server.deprecated.replace_with, function() - return Ui.Node { - Ui.HlTextNode { - { - { "Replace with: ", "LspInstallerMuted" }, - { server.deprecated.replace_with, "LspInstallerHighlighted" }, - }, - }, - Ui.Keybind("<CR>", "REPLACE_SERVER", { server.name, server.deprecated.replace_with }), - Ui.EmptyLine(), - } - end) - )) - end), - Ui.Table(Data.list_not_nil( - Data.lazy_when(server.is_installed, function() - return { - { "version", "LspInstallerMuted" }, - server.installed_version_err and { - "Unable to detect version.", - "LspInstallerMuted", - } or { server.installed_version or "Loading...", "" }, - } - end), - Data.lazy_when(#server.metadata.outdated_packages > 0, function() - return { - { "latest version", "LspInstallerGreen" }, - { - format_new_package_versions(server.metadata.outdated_packages), - "LspInstallerGreen", - }, - } - end), - Data.lazy_when(server.metadata.install_timestamp_seconds, function() - return { - { "installed", "LspInstallerMuted" }, - { format_time(server.metadata.install_timestamp_seconds), "" }, - } - end), - Data.when(not server.is_installed, { - { "filetypes", "LspInstallerMuted" }, - { server.metadata.filetypes, "" }, - }), - Data.when(server.is_installed, { - { "path", "LspInstallerMuted" }, - { server.metadata.install_dir, "String" }, - }), - { - { "homepage", "LspInstallerMuted" }, - server.metadata.homepage and { server.metadata.homepage, "LspInstallerLink" } or { - "-", - "LspInstallerMuted", - }, - } - )), - Ui.When(server.schema, function() - return Ui.Node { - Ui.EmptyLine(), - Ui.HlTextNode { - { - { - ("%s Server configuration schema"):format(server.has_expanded_schema and "↓" or "→"), - "LspInstallerLabel", - }, - { - (" (press enter to %s)"):format(server.has_expanded_schema and "collapse" or "expand"), - "Comment", - }, - }, - }, - Ui.Keybind("<CR>", "TOGGLE_SERVER_SETTINGS_SCHEMA", { server.name }), - Ui.When(server.has_expanded_schema, function() - return Indent { - Ui.HlTextNode { - { - { - "This is a read-only representation of the settings this server accepts. Note that some settings might not apply to neovim.", - "LspInstallerMuted", - }, - }, - { - { "For information on how to customize these settings, see ", "LspInstallerMuted" }, - { ":help lspconfig-setup", "LspInstallerHighlighted" }, - }, - }, - Ui.EmptyLine(), - ServerSettingsSchema(server, server.schema), - } - end), - Ui.EmptyLine(), - } - end) - )) -end - ----@param servers ServerState[] ----@param props ServerGroupProps -local function InstalledServers(servers, props) - return Ui.Node(Data.list_map( - ---@param server ServerState - function(server) - local is_expanded = props.expanded_server == server.name - return Ui.Node { - Ui.HlTextNode { - Data.list_not_nil( - { settings.current.ui.icons.server_installed, "LspInstallerGreen" }, - { " " .. server.name .. " ", "" }, - { server.hints, "Comment" }, - Data.when(server.deprecated, { " deprecated", "LspInstallerOrange" }), - Data.when( - #server.metadata.outdated_packages > 0 and not is_expanded, - { " new version available", "LspInstallerGreen" } - ) - ), - }, - Ui.Keybind(settings.current.ui.keymaps.toggle_server_expand, "EXPAND_SERVER", { server.name }), - Ui.Keybind(settings.current.ui.keymaps.update_server, "INSTALL_SERVER", { server.name }), - Ui.Keybind(settings.current.ui.keymaps.check_server_version, "CHECK_SERVER_VERSION", { server.name }), - Ui.Keybind(settings.current.ui.keymaps.uninstall_server, "UNINSTALL_SERVER", { server.name }), - Ui.When(is_expanded, function() - return Indent { - ServerMetadata(server), - } - end), - } - end, - servers - )) -end - ----@param server ServerState -local function TailedOutput(server) - return Ui.HlTextNode(Data.list_map(function(line) - return { { line, "LspInstallerMuted" } } - end, server.installer.tailed_output)) -end - ----@param output string[] ----@return string -local function get_last_non_empty_line(output) - for i = #output, 1, -1 do - local line = output[i] - if #line > 0 then - return line - end - end - return "" -end - ----@param servers ServerState[] -local function PendingServers(servers) - return Ui.Node(Data.list_map(function(_server) - ---@type ServerState - local server = _server - local has_failed = server.installer.has_run or server.uninstaller.has_run - local note = has_failed and "(failed)" or (server.installer.is_queued and "(queued)" or "(installing)") - return Ui.Node { - Ui.HlTextNode { - Data.list_not_nil( - { - settings.current.ui.icons.server_pending, - has_failed and "LspInstallerError" or "LspInstallerOrange", - }, - { " " .. server.name, server.installer.is_running and "" or "LspInstallerMuted" }, - { " " .. note, "Comment" }, - Data.when(not has_failed, { - (" " .. get_last_non_empty_line(server.installer.tailed_output)), - "Comment", - }) - ), - }, - Ui.Keybind(settings.current.ui.keymaps.install_server, "INSTALL_SERVER", { server.name }), - Ui.When(has_failed, function() - return Indent { Indent { TailedOutput(server) } } - end), - Ui.When( - server.uninstaller.error, - Indent { - Ui.HlTextNode { server.uninstaller.error, "Comment" }, - } - ), - } - end, servers)) -end - ----@param servers ServerState[] ----@param props ServerGroupProps -local function UninstalledServers(servers, props) - return Ui.Node(Data.list_map(function(_server) - ---@type ServerState - local server = _server - local is_prioritized = props.prioritized_servers[server.name] - local is_expanded = props.expanded_server == server.name - return Ui.Node { - Ui.HlTextNode { - Data.list_not_nil( - { - settings.current.ui.icons.server_uninstalled, - is_prioritized and "LspInstallerHighlighted" or "LspInstallerMuted", - }, - { " " .. server.name .. " ", "LspInstallerMuted" }, - { server.hints, "Comment" }, - Data.when(server.uninstaller.has_run, { " (uninstalled) ", "Comment" }), - Data.when(server.deprecated, { "deprecated ", "LspInstallerOrange" }) - ), - }, - Ui.Keybind(settings.current.ui.keymaps.toggle_server_expand, "EXPAND_SERVER", { server.name }), - Ui.Keybind(settings.current.ui.keymaps.install_server, "INSTALL_SERVER", { server.name }), - Ui.When(is_expanded, function() - return Indent { - ServerMetadata(server), - } - end), - } - end, servers)) -end - ----@alias ServerGroupProps {title: string, subtitle: string|nil, hide_when_empty: boolean|nil, servers: ServerState[][], expanded_server: string|nil, renderer: fun(servers: ServerState[], props: ServerGroupProps)} - ----@param props ServerGroupProps -local function ServerGroup(props) - local total_server_count = 0 - local chunks = props.servers - for i = 1, #chunks do - local servers = chunks[i] - total_server_count = total_server_count + #servers - end - - return Ui.When(total_server_count > 0 or not props.hide_when_empty, function() - return Ui.Node { - Ui.EmptyLine(), - ServerGroupHeading { - title = props.title, - subtitle = props.subtitle, - count = total_server_count, - }, - Indent(Data.list_map(function(servers) - return props.renderer(servers, props) - end, props.servers)), - } - end) -end - ----@param state StatusWinState -local function Servers(state) - local grouped_servers = { - installed = {}, - queued = {}, - session_installed = {}, - uninstall_failed = {}, - installing = {}, - install_failed = {}, - uninstalled_prioritized = {}, - uninstalled = {}, - session_uninstalled = {}, - } - - local servers, server_name_order, prioritized_servers, expanded_server = - state.servers, state.server_name_order, state.prioritized_servers, state.expanded_server - - -- giggity - for _, server_name in ipairs(server_name_order) do - local server = servers[server_name] - if server.installer.is_running then - grouped_servers.installing[#grouped_servers.installing + 1] = server - elseif server.installer.is_queued then - grouped_servers.queued[#grouped_servers.queued + 1] = server - elseif server.uninstaller.has_run then - if server.uninstaller.error then - grouped_servers.uninstall_failed[#grouped_servers.uninstall_failed + 1] = server - else - grouped_servers.session_uninstalled[#grouped_servers.session_uninstalled + 1] = server - end - elseif server.is_installed then - if server.installer.has_run then - grouped_servers.session_installed[#grouped_servers.session_installed + 1] = server - else - grouped_servers.installed[#grouped_servers.installed + 1] = server - end - elseif server.installer.has_run then - grouped_servers.install_failed[#grouped_servers.install_failed + 1] = server - else - if prioritized_servers[server.name] then - grouped_servers.uninstalled_prioritized[#grouped_servers.uninstalled_prioritized + 1] = server - else - grouped_servers.uninstalled[#grouped_servers.uninstalled + 1] = server - end - end - end - - return Ui.Node { - ServerGroup { - title = "Installed servers", - subtitle = state.server_version_check_completed_percentage ~= nil and { - { - "checking for new versions ", - "Comment", - }, - { - state.server_version_check_completed_percentage .. "%", - state.server_version_check_completed_percentage == 100 and "LspInstallerVersionCheckLoaderDone" - or "LspInstallerVersionCheckLoader", - }, - { - string.rep(" ", math.floor(state.server_version_check_completed_percentage / 5)), - state.server_version_check_completed_percentage == 100 and "LspInstallerVersionCheckLoaderDone" - or "LspInstallerVersionCheckLoader", - }, - }, - renderer = InstalledServers, - servers = { grouped_servers.session_installed, grouped_servers.installed }, - expanded_server = expanded_server, - }, - ServerGroup { - title = "Pending servers", - hide_when_empty = true, - renderer = PendingServers, - servers = { - grouped_servers.installing, - grouped_servers.queued, - grouped_servers.install_failed, - grouped_servers.uninstall_failed, - }, - expanded_server = expanded_server, - }, - ServerGroup { - title = "Available servers", - renderer = UninstalledServers, - servers = { - grouped_servers.session_uninstalled, - grouped_servers.uninstalled_prioritized, - grouped_servers.uninstalled, - }, - expanded_server = expanded_server, - prioritized_servers = prioritized_servers, - }, - } -end - ----@param server Server -local function create_initial_server_state(server) - ---@class ServerState - local server_state = { - name = server.name, - is_installed = server:is_installed(), - deprecated = server.deprecated, - hints = tostring(ServerHints.new(server)), - expanded_schema_properties = {}, - has_expanded_schema = false, - installed_version = nil, -- lazy - installed_version_err = nil, -- lazy - ---@type table - schema = nil, -- lazy - metadata = { - homepage = server.homepage, - ---@type number - install_timestamp_seconds = nil, -- lazy - install_dir = vim.fn.fnamemodify(server.root_dir, ":~"), - filetypes = table.concat(server:get_supported_filetypes(), ", "), - ---@type OutdatedPackage[] - outdated_packages = {}, - }, - installer = { - is_queued = false, - is_running = false, - has_run = false, - tailed_output = { "" }, - }, - uninstaller = { - has_run = false, - error = nil, - }, - } - return server_state -end - -local function normalize_chunks_line_endings(chunk, dest) - local chunk_lines = vim.split(chunk, "\n") - dest[#dest] = dest[#dest] .. chunk_lines[1] - for i = 2, #chunk_lines do - dest[#dest + 1] = chunk_lines[i] - end -end - -local function init(all_servers) - local filetype_map = require "nvim-lsp-installer._generated.filetype_map" - local window = display.new_view_only_win "LSP servers" - - window.view( - --- @param state StatusWinState - function(state) - return Indent { - Ui.Keybind(HELP_KEYMAP, "TOGGLE_HELP", nil, true), - Ui.Keybind(CLOSE_WINDOW_KEYMAP_1, "CLOSE_WINDOW", nil, true), - Ui.Keybind(CLOSE_WINDOW_KEYMAP_2, "CLOSE_WINDOW", nil, true), - Ui.Keybind(settings.current.ui.keymaps.check_outdated_servers, "CHECK_OUTDATED_SERVERS", nil, true), - Ui.Keybind(settings.current.ui.keymaps.update_all_servers, "UPDATE_ALL_SERVERS", nil, true), - Header { - is_showing_help = state.is_showing_help, - help_command_text = state.help_command_text, - }, - Ui.When(state.is_showing_help, function() - return Help(state.is_current_settings_expanded, state.vader_saber_ticks) - end), - Ui.When(not state.is_showing_help, function() - return Servers(state) - end), - } - end - ) - - ---@type table<string, ServerState> - local servers = {} - ---@type string[] - local server_name_order = {} - for i = 1, #all_servers do - local server = all_servers[i] - servers[server.name] = create_initial_server_state(server) - server_name_order[#server_name_order + 1] = server.name - end - - table.sort(server_name_order) - - ---@class StatusWinState - ---@field prioritized_servers string[] - local initial_state = { - server_name_order = server_name_order, - servers = servers, - server_version_check_completed_percentage = nil, - is_showing_help = false, - is_current_settings_expanded = false, - prioritized_servers = {}, - expanded_server = nil, - help_command_text = "", -- for "animating" the ":help" text when toggling the help window - vader_saber_ticks = 0, -- for "animating" the cowthvader lightsaber - } - - local mutate_state_generic, get_state_generic = window.init(initial_state) - -- Generics don't really work with higher-order functions so we cast it here. - ---@type fun(mutate_fn: fun(current_state: StatusWinState)) - local mutate_state = mutate_state_generic - ---@type fun(): StatusWinState - local get_state = get_state_generic - - local async_populate_server_metadata = a.scope(function(server_name) - a.scheduler() - local ok, server = lsp_servers.get_server(server_name) - if not ok then - return log.warn("Unable to get server when populating metadata.", server_name) - end - local fstat_ok, fstat = pcall(fs.fstat, server.root_dir) - mutate_state(function(state) - if fstat_ok then - state.servers[server.name].metadata.install_timestamp_seconds = fstat.mtime.sec - end - state.servers[server.name].schema = server:get_settings_schema() - end) - local version = version_check.check_server_version(server) - mutate_state(function(state) - if version:is_success() then - state.servers[server.name].installed_version = version:get_or_nil() - state.servers[server.name].installed_version_err = nil - else - state.servers[server.name].installed_version_err = true - end - end) - end) - - ---@param server_name string - local function expand_server(server_name) - mutate_state(function(state) - local should_expand = state.expanded_server ~= server_name - state.expanded_server = should_expand and server_name or nil - if should_expand then - async_populate_server_metadata(server_name) - end - end) - end - - ---@param server Server - ---@param requested_version string|nil - ---@param on_complete fun() - local function start_install(server, requested_version, on_complete) - mutate_state(function(state) - state.servers[server.name].installer.is_queued = false - state.servers[server.name].installer.is_running = true - end) - - log.fmt_info("Starting install server_name=%s, requested_version=%s", server.name, requested_version or "") - - server:install_attached({ - requested_server_version = requested_version, - stdio_sink = { - stdout = function(chunk) - mutate_state(function(state) - local tailed_output = state.servers[server.name].installer.tailed_output - normalize_chunks_line_endings(chunk, tailed_output) - end) - end, - stderr = function(chunk) - mutate_state(function(state) - local tailed_output = state.servers[server.name].installer.tailed_output - normalize_chunks_line_endings(chunk, tailed_output) - end) - end, - }, - }, function(success) - log.fmt_info("Installation completed server_name=%s, success=%s", server.name, success) - mutate_state(function(state) - if success then - -- release stdout/err output table.. hopefully ¯\_(ツ)_/¯ - state.servers[server.name].installer.tailed_output = { "" } - end - state.servers[server.name].is_installed = success - state.servers[server.name].installer.is_running = false - state.servers[server.name].installer.has_run = true - if not state.expanded_server then - -- Only automatically expand the server upon installation if none is already expanded, for UX reasons - expand_server(server.name) - elseif state.expanded_server == server.name then - -- Refresh server metadata - async_populate_server_metadata(server.name) - end - end) - on_complete() - end) - end - - -- We have a queue because installers have a tendency to hog resources. - local job_pool = JobExecutionPool:new { - size = settings.current.max_concurrent_installers, - } - ---@param server Server - ---@param version string|nil - local function install_server(server, version) - log.fmt_debug("Queuing server=%s, version=%s for installation", server.name, version or "") - local server_state = get_state().servers[server.name] - if server_state and (server_state.installer.is_running or server_state.installer.is_queued) then - log.debug("Installer is already queued/running", server.name) - return - end - mutate_state(function(state) - -- reset state - state.servers[server.name] = create_initial_server_state(server) - state.servers[server.name].installer.is_queued = true - end) - job_pool:supply(function(cb) - start_install(server, version, cb) - end) - end - - ---@param server Server - local function uninstall_server(server) - local server_state = get_state().servers[server.name] - if server_state and (server_state.installer.is_running or server_state.installer.is_queued) then - log.debug("Installer is already queued/running", server.name) - return - end - - local is_uninstalled, err = pcall(server.uninstall, server) - mutate_state(function(state) - -- reset state - state.servers[server.name] = create_initial_server_state(server) - if is_uninstalled then - state.servers[server.name].is_installed = false - end - state.servers[server.name].uninstaller.has_run = true - state.servers[server.name].uninstaller.error = err - end) - end - - local function mark_all_servers_uninstalled() - mutate_state(function(state) - for _, server_name in ipairs(lsp_servers.get_available_server_names()) do - if state.servers[server_name].is_installed then - state.servers[server_name].is_installed = false - state.servers[server_name].uninstaller.has_run = true - end - end - end) - end - - local make_animation = function(opts) - local animation_fn = opts[1] - local is_animating = false - local start_animation = function() - if is_animating then - return - end - local tick, start - - tick = function(current_tick) - animation_fn(current_tick) - if current_tick < opts.end_tick then - vim.defer_fn(function() - tick(current_tick + 1) - end, opts.delay_ms) - else - is_animating = false - if opts.iteration_delay_ms then - start(opts.iteration_delay_ms) - end - end - end - - start = function(delay_ms) - is_animating = true - if delay_ms then - vim.defer_fn(function() - tick(opts.start_tick) - end, delay_ms) - else - tick(opts.start_tick) - end - end - - start(opts.start_delay_ms) - - local function cancel() - is_animating = false - end - - return cancel - end - - return start_animation - end - - local start_help_command_animation - do - local help_command = ":help " - local help_command_len = #help_command - start_help_command_animation = make_animation { - function(tick) - mutate_state(function(state) - state.help_command_text = help_command:sub(help_command_len - tick, help_command_len) - end) - end, - start_tick = 0, - end_tick = help_command_len, - delay_ms = 80, - } - end - - local start_vader_saber_animation = make_animation { - function(tick) - mutate_state(function(state) - state.vader_saber_ticks = tick - end) - end, - start_tick = 0, - end_tick = 3, - delay_ms = 350, - iteration_delay_ms = 10000, - start_delay_ms = 1000, - } - - local function close() - if window then - window.close() - end - end - - local has_opened = false - - local function identify_outdated_servers(servers) - -- Sort servers the same way as in the UI, gives a more structured impression - table.sort(servers, function(a, b) - return a.name < b.name - end) - if #servers > 0 then - mutate_state(function(state) - state.server_version_check_completed_percentage = 0 - end) - end - outdated_servers.identify_outdated_servers(servers, function(check_result, progress) - mutate_state(function(state) - local completed_percentage = progress.completed / progress.total - state.server_version_check_completed_percentage = math.floor(completed_percentage * 100) - if completed_percentage == 1 then - vim.defer_fn(function() - mutate_state(function(state) - state.server_version_check_completed_percentage = nil - end) - end, 700) - end - - if check_result.success and check_result:has_outdated_packages() then - state.servers[check_result.server.name].metadata.outdated_packages = check_result.outdated_packages - end - end) - end) - end - - local function open() - local open_filetypes = {} - for _, open_bufnr in ipairs(vim.api.nvim_list_bufs()) do - table.insert(open_filetypes, vim.api.nvim_buf_get_option(open_bufnr, "filetype")) - end - - local prioritized_servers = {} - for _, filetype in ipairs(open_filetypes) do - if filetype_map[filetype] then - vim.list_extend(prioritized_servers, filetype_map[filetype]) - end - end - - mutate_state(function(state) - state.is_showing_help = false - state.prioritized_servers = Data.set_of(prioritized_servers) - end) - - if not has_opened then - -- Only do this automatically once - when opening the window the first time - vim.defer_fn(function() - identify_outdated_servers(lsp_servers.get_installed_servers()) - end, 100) - end - - window.open { - highlight_groups = { - "hi def LspInstallerHeader gui=bold guifg=#ebcb8b", - "hi def LspInstallerServerExpanded gui=italic", - "hi def LspInstallerHeading gui=bold", - "hi def LspInstallerGreen guifg=#a3be8c", - "hi def LspInstallerVaderSaber guifg=#f44747 gui=bold", - "hi def LspInstallerOrange ctermfg=222 guifg=#ebcb8b", - "hi def LspInstallerMuted guifg=#888888 ctermfg=144", - "hi def LspInstallerLabel gui=bold", - "hi def LspInstallerError ctermfg=203 guifg=#f44747", - "hi def LspInstallerHighlighted guifg=#56B6C2", - "hi def LspInstallerVersionCheckLoader gui=bold guifg=#222222 guibg=#888888", - "hi def LspInstallerVersionCheckLoaderDone gui=bold guifg=#222222 guibg=#a3be8c", - "hi def link LspInstallerLink LspInstallerHighlighted", - }, - effects = { - ["TOGGLE_HELP"] = function() - if not get_state().is_showing_help then - start_help_command_animation() - start_vader_saber_animation() - window.set_cursor { 1, 1 } - end - mutate_state(function(state) - state.is_showing_help = not state.is_showing_help - end) - end, - ["CLOSE_WINDOW"] = function() - close() - end, - ["CHECK_OUTDATED_SERVERS"] = function() - vim.schedule(function() - identify_outdated_servers(lsp_servers.get_installed_servers()) - end) - end, - ["CHECK_SERVER_VERSION"] = function(e) - local server_name = e.payload[1] - local ok, server = lsp_servers.get_server(server_name) - if ok then - identify_outdated_servers { server } - end - end, - ["TOGGLE_EXPAND_CURRENT_SETTINGS"] = function() - mutate_state(function(state) - state.is_current_settings_expanded = not state.is_current_settings_expanded - end) - end, - ["EXPAND_SERVER"] = function(e) - local server_name = e.payload[1] - expand_server(server_name) - end, - ["TOGGLE_SERVER_SETTINGS_SCHEMA"] = function(e) - local server_name = e.payload[1] - mutate_state(function(state) - state.servers[server_name].has_expanded_schema = - not state.servers[server_name].has_expanded_schema - end) - end, - ["TOGGLE_SERVER_SCHEMA_SETTING"] = function(e) - local server_name = e.payload.name - local key = e.payload.key - mutate_state(function(state) - state.servers[server_name].expanded_schema_properties[key] = - not state.servers[server_name].expanded_schema_properties[key] - end) - end, - ["INSTALL_SERVER"] = function(e) - local server_name = e.payload[1] - local ok, server = lsp_servers.get_server(server_name) - if ok then - install_server(server, nil) - end - end, - ["UPDATE_ALL_SERVERS"] = function() - local installed_servers = lsp_servers.get_installed_servers() - local state = get_state() - local outdated_servers = vim.tbl_filter(function(server) - return #state.servers[server.name].metadata.outdated_packages > 0 - end, installed_servers) - -- Install servers that are identified as outdated, otherwise update all installed servers. - local servers_to_update = #outdated_servers > 0 and outdated_servers or installed_servers - for _, server in ipairs(servers_to_update) do - install_server(server, nil) - end - end, - ["UNINSTALL_SERVER"] = function(e) - local server_name = e.payload[1] - local ok, server = lsp_servers.get_server(server_name) - if ok then - uninstall_server(server) - end - end, - ["REPLACE_SERVER"] = function(e) - local old_server_name, new_server_name = e.payload[1], e.payload[2] - local old_ok, old_server = lsp_servers.get_server(old_server_name) - local new_ok, new_server = lsp_servers.get_server(new_server_name) - if old_ok and new_ok then - uninstall_server(old_server) - install_server(new_server) - end - end, - }, - } - has_opened = true - end - - return { - open = open, - close = close, - install_server = install_server, - uninstall_server = uninstall_server, - mark_all_servers_uninstalled = mark_all_servers_uninstalled, - } -end - -local win -return function() - if win then - return win - end - win = init(lsp_servers.get_available_servers()) - return win -end |
