diff options
| author | William Boman <william@redwill.se> | 2021-10-25 14:55:47 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-25 14:55:47 +0200 |
| commit | f60d78a29fbe772e0724ee0853a13894b9765fdf (patch) | |
| tree | adf8fd822587d779c5b90d5ed30987a982fd497e /lua/nvim-lsp-installer/installers | |
| parent | fix :LspPrintInstalled (diff) | |
| download | mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.tar mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.tar.gz mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.tar.bz2 mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.tar.lz mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.tar.xz mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.tar.zst mason-f60d78a29fbe772e0724ee0853a13894b9765fdf.zip | |
add proper emmylua annotations (#196)
Diffstat (limited to 'lua/nvim-lsp-installer/installers')
| -rw-r--r-- | lua/nvim-lsp-installer/installers/composer.lua | 70 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/context.lua | 16 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/gem.lua | 5 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/go.lua | 4 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/init.lua | 41 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/npm.lua | 53 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/pip3.lua | 6 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/shell.lua | 15 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/installers/std.lua | 64 |
9 files changed, 207 insertions, 67 deletions
diff --git a/lua/nvim-lsp-installer/installers/composer.lua b/lua/nvim-lsp-installer/installers/composer.lua index d206cc46..ebe591d4 100644 --- a/lua/nvim-lsp-installer/installers/composer.lua +++ b/lua/nvim-lsp-installer/installers/composer.lua @@ -8,6 +8,7 @@ local process = require "nvim-lsp-installer.process" local composer = platform.is_win and "composer.bat" or "composer" +---@param installer ServerInstallerFunction local function ensure_composer(installer) return installers.pipe { std.ensure_executables { @@ -20,45 +21,54 @@ end local M = {} +---@param packages string[] @The Gem packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. function M.packages(packages) - return ensure_composer(function(server, callback, context) - local c = process.chain { - cwd = server.root_dir, - stdio_sink = context.stdio_sink, - } + return ensure_composer( + ---@type ServerInstallerFunction + function(server, callback, context) + local c = process.chain { + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + } - if not (fs.file_exists(path.concat { server.root_dir, "composer.json" })) then - c.run(composer, { "init", "--no-interaction", "--stability=dev" }) - c.run(composer, { "config", "prefer-stable", "true" }) - end + if not (fs.file_exists(path.concat { server.root_dir, "composer.json" })) then + c.run(composer, { "init", "--no-interaction", "--stability=dev" }) + c.run(composer, { "config", "prefer-stable", "true" }) + end - local pkgs = Data.list_copy(packages or {}) - if context.requested_server_version then - -- The "head" package is the recipient for the requested version. It's.. by design... don't ask. - pkgs[1] = ("%s:%s"):format(pkgs[1], context.requested_server_version) - end + local pkgs = Data.list_copy(packages or {}) + if context.requested_server_version then + -- The "head" package is the recipient for the requested version. It's.. by design... don't ask. + pkgs[1] = ("%s:%s"):format(pkgs[1], context.requested_server_version) + end - c.run(composer, vim.list_extend({ "require" }, pkgs)) - c.spawn(callback) - end) + c.run(composer, vim.list_extend({ "require" }, pkgs)) + c.spawn(callback) + end + ) end function M.install() - return ensure_composer(function(server, callback, context) - process.spawn(composer, { - args = { - "install", - "--no-interaction", - "--no-dev", - "--optimize-autoloader", - "--classmap-authoritative", - }, - cwd = server.root_dir, - stdio_sink = context.stdio_sink, - }, callback) - end) + return ensure_composer( + ---@type ServerInstallerFunction + function(server, callback, context) + process.spawn(composer, { + args = { + "install", + "--no-interaction", + "--no-dev", + "--optimize-autoloader", + "--classmap-authoritative", + }, + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }, callback) + end + ) end +---@param root_dir string @The directory to resolve the executable from. +---@param executable string function M.executable(root_dir, executable) return path.concat { root_dir, "vendor", "bin", platform.is_win and ("%s.bat"):format(executable) or executable } end diff --git a/lua/nvim-lsp-installer/installers/context.lua b/lua/nvim-lsp-installer/installers/context.lua index c36a9e65..13775fc0 100644 --- a/lua/nvim-lsp-installer/installers/context.lua +++ b/lua/nvim-lsp-installer/installers/context.lua @@ -6,6 +6,8 @@ local platform = require "nvim-lsp-installer.platform" local M = {} +---@param url string @The url to fetch. +---@param callback fun(err: string|nil, raw_data: string) local function fetch(url, callback) local stdio = process.in_memory_sink() log.fmt_debug("Fetching URL %s", url) @@ -57,7 +59,9 @@ local function fetch(url, callback) } end +---@param repo string @The GitHub repo ("username/repo"). function M.use_github_release(repo) + ---@type ServerInstallerFunction return function(server, callback, context) if context.requested_server_version then log.fmt_debug( @@ -84,6 +88,8 @@ function M.use_github_release(repo) end end +---@param repo string @The GitHub report ("username/repo"). +---@param file string @The name of a file availabine in the provided repo's GitHub releases. function M.use_github_release_file(repo, file) return installers.pipe { M.use_github_release(repo), @@ -117,14 +123,20 @@ function M.use_github_release_file(repo, file) } end +---Access the context ojbect to create a new installer. +---@param fn fun(context: ServerInstallContext): ServerInstallerFunction function M.capture(fn) - return function(server, callback, context, ...) + ---@type ServerInstallerFunction + return function(server, callback, context) local installer = fn(context) - installer(server, callback, context, ...) + installer(server, callback, context) end end +---Update the context object. +---@param fn fun(context: ServerInstallContext): ServerInstallerFunction function M.set(fn) + ---@type ServerInstallerFunction return function(_, callback, context) fn(context) callback(true) diff --git a/lua/nvim-lsp-installer/installers/gem.lua b/lua/nvim-lsp-installer/installers/gem.lua index 091cda27..331be055 100644 --- a/lua/nvim-lsp-installer/installers/gem.lua +++ b/lua/nvim-lsp-installer/installers/gem.lua @@ -9,12 +9,14 @@ local M = {} local gem = platform.is_win and "gem.cmd" or "gem" +---@param packages string[] @The Gem packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. function M.packages(packages) return installers.pipe { std.ensure_executables { { "ruby", "ruby was not found in path, refer to https://wiki.openstack.org/wiki/RubyGems." }, { "gem", "gem was not found in path, refer to https://wiki.openstack.org/wiki/RubyGems." }, }, + ---@type ServerInstallerFunction function(server, callback, context) local pkgs = Data.list_copy(packages or {}) if context.requested_server_version then @@ -38,10 +40,13 @@ function M.packages(packages) } end +---@param root_dir string @The directory to resolve the executable from. +---@param executable string function M.executable(root_dir, executable) return path.concat { root_dir, "bin", executable } end +---@param root_dir string function M.env(root_dir) return { GEM_HOME = root_dir, diff --git a/lua/nvim-lsp-installer/installers/go.lua b/lua/nvim-lsp-installer/installers/go.lua index 005ce842..c2dbcb37 100644 --- a/lua/nvim-lsp-installer/installers/go.lua +++ b/lua/nvim-lsp-installer/installers/go.lua @@ -6,9 +6,11 @@ local process = require "nvim-lsp-installer.process" local M = {} +---@param packages string[] @The Go packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. function M.packages(packages) return installers.pipe { std.ensure_executables { { "go", "go was not found in path, refer to https://golang.org/doc/install." } }, + ---@type ServerInstallerFunction function(server, callback, context) local pkgs = Data.list_copy(packages or {}) local c = process.chain { @@ -34,6 +36,8 @@ function M.packages(packages) } end +---@param root_dir string @The directory to resolve the executable from. +---@param executable string function M.executable(root_dir, executable) return path.concat { root_dir, executable } end diff --git a/lua/nvim-lsp-installer/installers/init.lua b/lua/nvim-lsp-installer/installers/init.lua index 83b46a1b..f8490586 100644 --- a/lua/nvim-lsp-installer/installers/init.lua +++ b/lua/nvim-lsp-installer/installers/init.lua @@ -4,6 +4,18 @@ local Data = require "nvim-lsp-installer.data" local M = {} +---@alias ServerInstallCallback fun(success: boolean) + +---@class ServerInstallContext +---@field requested_server_version string|nil @The version requested by the user. +---@field stdio_sink StdioSink +---@field github_release_file string|nil @Only available if context.use_github_release_file has been called. + +---@alias ServerInstallerFunction fun(server: Server, callback: ServerInstallCallback, context: ServerInstallContext) + +--- Composes multiple installer functions into one. +---@param installers ServerInstallerFunction[] +---@return ServerInstallerFunction function M.pipe(installers) if #installers == 0 then error "No installers to pipe." @@ -33,6 +45,14 @@ function M.pipe(installers) end end +--- Composes multiple installer function into one - in reversed order. +---@param installers ServerInstallerFunction[] +function M.compose(installers) + return M.pipe(Data.list_reverse(installers)) +end + +---@param installers ServerInstallerFunction[] +---@return ServerInstallerFunction @An installer function that will serially execute the provided installers, until the first one succeeds. function M.first_successful(installers) if #installers == 0 then error "No installers to pipe." @@ -64,11 +84,9 @@ function M.first_successful(installers) end end --- much fp, very wow -function M.compose(installers) - return M.pipe(Data.list_reverse(installers)) -end - +--- Wraps the provided server installer to always succeeds. +---@param installer ServerInstallerFunction +---@return ServerInstallerFunction function M.always_succeed(installer) return function(server, callback, context) installer(server, function() @@ -77,8 +95,11 @@ function M.always_succeed(installer) end end +---@param platform_table table<Platform, ServerInstallerFunction> +---@return ServerInstallerFunction | nil local function get_by_platform(platform_table) if platform.is_mac then + platform_table.mac() return platform_table.mac or platform_table.unix elseif platform.is_linux then return platform_table.linux or platform_table.unix @@ -91,7 +112,10 @@ local function get_by_platform(platform_table) end end --- non-exhaustive +--- Creates a server installer that executes the given installer for the current platform. +--- If there is no server installer provided for the current platform, the installer will instantly exit successfully. +---@param platform_table table<Platform, ServerInstallerFunction> +---@return ServerInstallerFunction function M.on(platform_table) return function(server, callback, context) local installer = get_by_platform(platform_table) @@ -107,7 +131,10 @@ function M.on(platform_table) end end --- exhaustive +--- Creates a server installer that executes the given installer for the current platform. +--- If there is no server installer provided for the current platform, the installer will instantly exit with a failure. +---@param platform_table table<Platform, ServerInstallerFunction> +---@return ServerInstallerFunction function M.when(platform_table) return function(server, callback, context) local installer = get_by_platform(platform_table) diff --git a/lua/nvim-lsp-installer/installers/npm.lua b/lua/nvim-lsp-installer/installers/npm.lua index b165d5f1..d6805b0e 100644 --- a/lua/nvim-lsp-installer/installers/npm.lua +++ b/lua/nvim-lsp-installer/installers/npm.lua @@ -10,6 +10,7 @@ local M = {} local npm = platform.is_win and "npm.cmd" or "npm" +---@param installer ServerInstallerFunction local function ensure_npm(installer) return installers.pipe { std.ensure_executables { @@ -24,13 +25,16 @@ local function ensure_npm(installer) end local function create_installer(read_version_from_context) + ---@param packages string[] return function(packages) - return ensure_npm(function(server, callback, context) - local pkgs = Data.list_copy(packages or {}) - local c = process.chain { - cwd = server.root_dir, - stdio_sink = context.stdio_sink, - } + return ensure_npm( + ---@type ServerInstallerFunction + function(server, callback, context) + local pkgs = Data.list_copy(packages or {}) + local c = process.chain { + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + } -- stylua: ignore start if not (fs.dir_exists(path.concat { server.root_dir, "node_modules" }) or fs.file_exists(path.concat { server.root_dir, "package.json" })) @@ -43,17 +47,25 @@ local function create_installer(read_version_from_context) pkgs[1] = ("%s@%s"):format(pkgs[1], context.requested_server_version) end - -- stylua: ignore end - c.run(npm, vim.list_extend({ "install" }, pkgs)) - c.spawn(callback) - end) + -- stylua: ignore end + c.run(npm, vim.list_extend({ "install" }, pkgs)) + c.spawn(callback) + end + ) end end +---Creates an installer that installs the provided packages. Will respect user's requested version. M.packages = create_installer(true) +---Creates an installer that installs the provided packages. Will NOT respect user's requested version. +---This is useful in situation where there's a need to install an auxiliary npm package. M.install = create_installer(false) +---Creates a server installer that executes the given executable. +---@param executable string +---@param args string[] function M.exec(executable, args) + ---@type ServerInstallerFunction return function(server, callback, context) process.spawn(M.executable(server.root_dir, executable), { args = args, @@ -63,16 +75,23 @@ function M.exec(executable, args) end end +---Creates a server installer that runs the given script. +---@param script string @The npm script to run (npm run). function M.run(script) - return ensure_npm(function(server, callback, context) - process.spawn(npm, { - args = { "run", script }, - cwd = server.root_dir, - stdio_sink = context.stdio_sink, - }, callback) - end) + return ensure_npm( + ---@type ServerInstallerFunction + function(server, callback, context) + process.spawn(npm, { + args = { "run", script }, + cwd = server.root_dir, + stdio_sink = context.stdio_sink, + }, callback) + end + ) end +---@param root_dir string @The directory to resolve the executable from. +---@param executable string function M.executable(root_dir, executable) return path.concat { root_dir, diff --git a/lua/nvim-lsp-installer/installers/pip3.lua b/lua/nvim-lsp-installer/installers/pip3.lua index 8ae3d2db..6b593858 100644 --- a/lua/nvim-lsp-installer/installers/pip3.lua +++ b/lua/nvim-lsp-installer/installers/pip3.lua @@ -10,6 +10,8 @@ local M = {} local REL_INSTALL_DIR = "venv" +---@param python_executable string +---@param packages string[] local function create_installer(python_executable, packages) return installers.pipe { std.ensure_executables { @@ -18,6 +20,7 @@ local function create_installer(python_executable, packages) ("%s was not found in path. Refer to https://www.python.org/downloads/."):format(python_executable), }, }, + ---@type ServerInstallerFunction function(server, callback, context) local pkgs = Data.list_copy(packages or {}) local c = process.chain { @@ -40,12 +43,15 @@ local function create_installer(python_executable, packages) } end +---@param packages string[] @The pip packages to install. The first item in this list will be the recipient of the server version, should the user request a specific one. function M.packages(packages) local py3 = create_installer("python3", packages) local py = create_installer("python", packages) return installers.first_successful(platform.is_win and { py, py3 } or { py3, py }) -- see https://github.com/williamboman/nvim-lsp-installer/issues/128 end +---@param root_dir string @The directory to resolve the executable from. +---@param executable string function M.executable(root_dir, executable) return path.concat { root_dir, REL_INSTALL_DIR, platform.is_win and "Scripts" or "bin", executable } end diff --git a/lua/nvim-lsp-installer/installers/shell.lua b/lua/nvim-lsp-installer/installers/shell.lua index 752a216c..35f0cf6e 100644 --- a/lua/nvim-lsp-installer/installers/shell.lua +++ b/lua/nvim-lsp-installer/installers/shell.lua @@ -3,7 +3,9 @@ local process = require "nvim-lsp-installer.process" local M = {} +---@param opts {shell: string, cmd: string[], env: table|nil} local function shell(opts) + ---@type ServerInstallerFunction return function(server, callback, context) local _, stdio = process.spawn(opts.shell, { cwd = server.root_dir, @@ -21,6 +23,8 @@ local function shell(opts) end end +---@param raw_script string @The bash script to execute as-is. +---@param opts {prefix: string, env: table} function M.bash(raw_script, opts) local default_opts = { prefix = "set -euo pipefail;", @@ -35,6 +39,8 @@ function M.bash(raw_script, opts) } end +---@param raw_script string @The sh script to execute as-is. +---@param opts {prefix: string, env: table} function M.sh(raw_script, opts) local default_opts = { prefix = "set -eu;", @@ -49,6 +55,8 @@ function M.sh(raw_script, opts) } end +---@param raw_script string @The cmd.exe script to execute as-is. +---@param opts {env: table} function M.cmd(raw_script, opts) local default_opts = { env = {}, @@ -62,6 +70,8 @@ function M.cmd(raw_script, opts) } end +---@param raw_script string @The powershell script to execute as-is. +---@param opts {prefix: string, env: table} function M.powershell(raw_script, opts) local default_opts = { env = {}, @@ -77,10 +87,15 @@ function M.powershell(raw_script, opts) } end +---@deprecated Unsafe. +---@param url string @The url to the powershell script to execute. +---@param opts {prefix: string, env: table} function M.remote_powershell(url, opts) return M.powershell(("iwr -UseBasicParsing %q | iex"):format(url), opts) end +---@param raw_script string @A script that is compatible with bash and cmd.exe. +---@param opts {env: table} function M.polyshell(raw_script, opts) local default_opts = { env = {}, diff --git a/lua/nvim-lsp-installer/installers/std.lua b/lua/nvim-lsp-installer/installers/std.lua index c011279d..0e060351 100644 --- a/lua/nvim-lsp-installer/installers/std.lua +++ b/lua/nvim-lsp-installer/installers/std.lua @@ -7,8 +7,11 @@ local shell = require "nvim-lsp-installer.installers.shell" local M = {} +---@param url string @The url to download. +---@param out_file string @The relative path to where to write the contents of the url. function M.download_file(url, out_file) return installers.when { + ---@type ServerInstallerFunction unix = function(server, callback, context) context.stdio_sink.stdout(("Downloading file %q...\n"):format(url)) process.attempt { @@ -31,9 +34,12 @@ function M.download_file(url, out_file) } end +---@param file string @The relative path to the file to unzip. +---@param dest string|nil @The destination of the unzip (defaults to "."). function M.unzip(file, dest) return installers.pipe { installers.when { + ---@type ServerInstallerFunction unix = function(server, callback, context) process.spawn("unzip", { args = { "-d", dest, file }, @@ -47,6 +53,8 @@ function M.unzip(file, dest) } end +---@see unzip(). +---@param url string @The url of the .zip file. function M.unzip_remote(url, dest) return installers.pipe { M.download_file(url, "archive.zip"), @@ -54,8 +62,10 @@ function M.unzip_remote(url, dest) } end +---@param file string @The relative path to the tar file to extract. function M.untar(file) return installers.pipe { + ---@type ServerInstallerFunction function(server, callback, context) process.spawn("tar", { args = { "-xvf", file }, @@ -67,8 +77,10 @@ function M.untar(file) } end +---@param file string local function win_extract(file) return installers.pipe { + ---@type ServerInstallerFunction function(server, callback, context) -- The trademarked "throw shit until it sticks" technique local sevenzip = process.lazy_spawn("7z", { @@ -95,6 +107,7 @@ local function win_extract(file) } end +---@param file string local function win_untarxz(file) return installers.pipe { win_extract(file), @@ -102,8 +115,10 @@ local function win_untarxz(file) } end +---@param file string local function win_arc_unarchive(file) return installers.pipe { + ---@type ServerInstallerFunction function(server, callback, context) context.stdio_sink.stdout "Attempting to unarchive using arc." process.spawn("arc", { @@ -116,6 +131,7 @@ local function win_arc_unarchive(file) } end +---@param url string @The url to the .tar.xz file to extract. function M.untarxz_remote(url) return installers.pipe { M.download_file(url, "archive.tar.xz"), @@ -129,6 +145,7 @@ function M.untarxz_remote(url) } end +---@param url string @The url to the .tar.gz file to extract. function M.untargz_remote(url) return installers.pipe { M.download_file(url, "archive.tar.gz"), @@ -136,8 +153,10 @@ function M.untargz_remote(url) } end +---@param file string @The relative path to the file to gunzip. function M.gunzip(file) return installers.when { + ---@type ServerInstallerFunction unix = function(server, callback, context) process.spawn("gzip", { args = { "-d", file }, @@ -149,6 +168,9 @@ function M.gunzip(file) } end +---@see gunzip() +---@param url string @The url to the .gz file to extract. +---@param out_file string|nil @The name of the extracted .gz file. function M.gunzip_remote(url, out_file) local archive = ("%s.gz"):format(out_file or "archive") return installers.pipe { @@ -158,7 +180,10 @@ function M.gunzip_remote(url, out_file) } end +---Recursively deletes the provided path. Will fail on paths that are not inside the configured install_root_dir. +---@param rel_path string @The relative path to the file/directory to remove. function M.rmrf(rel_path) + ---@type ServerInstallerFunction return function(server, callback, context) local abs_path = path.concat { server.root_dir, rel_path } context.stdio_sink.stdout(("Deleting %q\n"):format(abs_path)) @@ -174,7 +199,10 @@ function M.rmrf(rel_path) end end +---Shallow git clone. +---@param repo_url string function M.git_clone(repo_url) + ---@type ServerInstallerFunction return function(server, callback, context) local c = process.chain { cwd = server.root_dir, @@ -192,7 +220,9 @@ function M.git_clone(repo_url) end end +---@param opts {args: string[]} function M.gradlew(opts) + ---@type ServerInstallerFunction return function(server, callback, context) process.spawn(path.concat { server.root_dir, platform.is_win and "gradlew.bat" or "gradlew" }, { args = opts.args, @@ -202,23 +232,32 @@ function M.gradlew(opts) end end +---Creates an installer that ensures that the provided executables are available in the current runtime. +---@param executables string[][] @A list of (executable, error_msg) tuples. +---@return ServerInstallerFunction function M.ensure_executables(executables) - return vim.schedule_wrap(function(_, callback, context) - local has_error = false - for i = 1, #executables do - local entry = executables[i] - local executable = entry[1] - local error_msg = entry[2] - if vim.fn.executable(executable) ~= 1 then - has_error = true - context.stdio_sink.stderr(error_msg .. "\n") + return vim.schedule_wrap( + ---@type ServerInstallerFunction + function(_, callback, context) + local has_error = false + for i = 1, #executables do + local entry = executables[i] + local executable = entry[1] + local error_msg = entry[2] + if vim.fn.executable(executable) ~= 1 then + has_error = true + context.stdio_sink.stderr(error_msg .. "\n") + end end + callback(not has_error) end - callback(not has_error) - end) + ) end +---@path old_path string @The relative path to the file/dir to rename. +---@path new_path string @The relative path to what to rename the file/dir to. function M.rename(old_path, new_path) + ---@type ServerInstallerFunction return function(server, callback, context) local ok = pcall( fs.rename, @@ -232,8 +271,11 @@ function M.rename(old_path, new_path) end end +---@param flags string[] @The chmod flags to apply. +---@param files string[] @A list of relative paths to apply the chmod on. function M.chmod(flags, files) return installers.on { + ---@type ServerInstallerFunction unix = function(server, callback, context) process.spawn("chmod", { args = vim.list_extend({ flags }, files), |
