diff options
Diffstat (limited to 'lua')
61 files changed, 527 insertions, 104 deletions
diff --git a/lua/nvim-lsp-installer/data.lua b/lua/nvim-lsp-installer/data.lua index 901c293a..b5689142 100644 --- a/lua/nvim-lsp-installer/data.lua +++ b/lua/nvim-lsp-installer/data.lua @@ -33,6 +33,21 @@ function Data.list_map(fn, list) return result end +function Data.table_pack(...) + return { n = select("#", ...), ... } +end + +function Data.list_not_nil(...) + local result = {} + local args = Data.table_pack(...) + for i = 1, args.n do + if args[i] ~= nil then + result[#result + 1] = args[i] + end + end + return result +end + function Data.tbl_pack(...) return { n = select("#", ...), ... } end @@ -41,6 +56,10 @@ function Data.when(condition, value) return condition and value or nil end +function Data.lazy(condition, fn) + return condition and fn() or nil +end + function Data.coalesce(...) local args = Data.tbl_pack(...) for i = 1, args.n do diff --git a/lua/nvim-lsp-installer/server.lua b/lua/nvim-lsp-installer/server.lua index 4c8d4e65..1240d349 100644 --- a/lua/nvim-lsp-installer/server.lua +++ b/lua/nvim-lsp-installer/server.lua @@ -17,6 +17,9 @@ M.Server.__index = M.Server --@param opts table -- @field name (string) The name of the LSP server. This MUST correspond with lspconfig's naming. -- +-- @field homepage (string) A URL to the homepage of this server. This is for example where users can +-- report issues and receive support. +-- -- @field installer (function) The function that installs the LSP (see the .installers module). The function signature should be `function (server, callback)`, where -- `server` is the Server instance being installed, and `callback` is a function that must be called upon completion. The `callback` function -- has the signature `function (success, result)`, where `success` is a boolean and `result` is of any type (similar to `pcall`). @@ -37,6 +40,7 @@ function M.Server:new(opts) return setmetatable({ name = opts.name, root_dir = opts.root_dir, + homepage = opts.homepage, _root_dir = opts.root_dir, -- @deprecated Use the `root_dir` property instead. _installer = type(opts.installer) == "function" and opts.installer or installers.pipe(opts.installer), _default_options = opts.default_options, diff --git a/lua/nvim-lsp-installer/servers/angularls/init.lua b/lua/nvim-lsp-installer/servers/angularls/init.lua index 89c62741..5a545cd2 100644 --- a/lua/nvim-lsp-installer/servers/angularls/init.lua +++ b/lua/nvim-lsp-installer/servers/angularls/init.lua @@ -18,6 +18,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://angular.io/guide/language-service", installer = npm.packages { "@angular/language-server" }, default_options = { cmd = { diff --git a/lua/nvim-lsp-installer/servers/ansiblels/init.lua b/lua/nvim-lsp-installer/servers/ansiblels/init.lua index a3903146..46afb9a1 100644 --- a/lua/nvim-lsp-installer/servers/ansiblels/init.lua +++ b/lua/nvim-lsp-installer/servers/ansiblels/init.lua @@ -7,6 +7,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/ansible/ansible-language-server", installer = { std.git_clone "https://github.com/ansible/ansible-language-server", npm.install { "npm@latest" }, -- ansiblels has quite a strict npm version requirement diff --git a/lua/nvim-lsp-installer/servers/bashls/init.lua b/lua/nvim-lsp-installer/servers/bashls/init.lua index 7839131e..a670d6fc 100644 --- a/lua/nvim-lsp-installer/servers/bashls/init.lua +++ b/lua/nvim-lsp-installer/servers/bashls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/bash-lsp/bash-language-server", installer = npm.packages { "bash-language-server" }, default_options = { cmd = { npm.executable(root_dir, "bash-language-server"), "start" }, diff --git a/lua/nvim-lsp-installer/servers/bicep/init.lua b/lua/nvim-lsp-installer/servers/bicep/init.lua index 3e92e700..28e010b0 100644 --- a/lua/nvim-lsp-installer/servers/bicep/init.lua +++ b/lua/nvim-lsp-installer/servers/bicep/init.lua @@ -7,6 +7,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/Azure/bicep", installer = { std.ensure_executables { { "dotnet", "dotnet is required to run the bicep language server." }, diff --git a/lua/nvim-lsp-installer/servers/clangd/init.lua b/lua/nvim-lsp-installer/servers/clangd/init.lua index bf8494e7..63b17b5f 100644 --- a/lua/nvim-lsp-installer/servers/clangd/init.lua +++ b/lua/nvim-lsp-installer/servers/clangd/init.lua @@ -12,6 +12,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://clangd.llvm.org", installer = { context.github_release_file("clangd/clangd", function(version) return Data.coalesce( diff --git a/lua/nvim-lsp-installer/servers/clojure_lsp/init.lua b/lua/nvim-lsp-installer/servers/clojure_lsp/init.lua index bbdde873..8fb9d92b 100644 --- a/lua/nvim-lsp-installer/servers/clojure_lsp/init.lua +++ b/lua/nvim-lsp-installer/servers/clojure_lsp/init.lua @@ -9,6 +9,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://clojure-lsp.io", installer = { context.github_release_file( "clojure-lsp/clojure-lsp", diff --git a/lua/nvim-lsp-installer/servers/cmake/init.lua b/lua/nvim-lsp-installer/servers/cmake/init.lua index 9fe9de23..38df47b3 100644 --- a/lua/nvim-lsp-installer/servers/cmake/init.lua +++ b/lua/nvim-lsp-installer/servers/cmake/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/regen100/cmake-language-server", installer = pip3.packages { "cmake-language-server" }, default_options = { cmd = { pip3.executable(root_dir, "cmake-language-server") }, diff --git a/lua/nvim-lsp-installer/servers/denols/init.lua b/lua/nvim-lsp-installer/servers/denols/init.lua index 85245cf1..d09d3957 100644 --- a/lua/nvim-lsp-installer/servers/denols/init.lua +++ b/lua/nvim-lsp-installer/servers/denols/init.lua @@ -11,6 +11,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://deno.land/x/deno/cli/lsp", installer = { context.github_release_file( "denoland/deno", diff --git a/lua/nvim-lsp-installer/servers/diagnosticls/init.lua b/lua/nvim-lsp-installer/servers/diagnosticls/init.lua index 9a80eadc..3a48d13a 100644 --- a/lua/nvim-lsp-installer/servers/diagnosticls/init.lua +++ b/lua/nvim-lsp-installer/servers/diagnosticls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/iamcco/diagnostic-languageserver", installer = npm.packages { "diagnostic-languageserver" }, default_options = { cmd = { npm.executable(root_dir, "diagnostic-languageserver"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/dockerls/init.lua b/lua/nvim-lsp-installer/servers/dockerls/init.lua index 7ea76d2e..621eb8ed 100644 --- a/lua/nvim-lsp-installer/servers/dockerls/init.lua +++ b/lua/nvim-lsp-installer/servers/dockerls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/rcjsuen/dockerfile-language-server-nodejs", installer = npm.packages { "dockerfile-language-server-nodejs" }, default_options = { cmd = { npm.executable(root_dir, "docker-langserver"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/dotls/init.lua b/lua/nvim-lsp-installer/servers/dotls/init.lua index 438f6f88..bd2deedf 100644 --- a/lua/nvim-lsp-installer/servers/dotls/init.lua +++ b/lua/nvim-lsp-installer/servers/dotls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/nikeee/dot-language-server", installer = npm.packages { "dot-language-server" }, default_options = { cmd = { npm.executable(root_dir, "dot-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/efm/init.lua b/lua/nvim-lsp-installer/servers/efm/init.lua index 56037305..875b3884 100644 --- a/lua/nvim-lsp-installer/servers/efm/init.lua +++ b/lua/nvim-lsp-installer/servers/efm/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/mattn/efm-langserver", installer = go.packages { "github.com/mattn/efm-langserver" }, default_options = { cmd = { go.executable(root_dir, "efm-langserver") }, diff --git a/lua/nvim-lsp-installer/servers/elixirls/init.lua b/lua/nvim-lsp-installer/servers/elixirls/init.lua index ecb0cb00..4cd941f0 100644 --- a/lua/nvim-lsp-installer/servers/elixirls/init.lua +++ b/lua/nvim-lsp-installer/servers/elixirls/init.lua @@ -7,6 +7,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/elixir-lsp/elixir-ls", installer = { context.github_release_file("elixir-lsp/elixir-ls", "elixir-ls.zip"), context.capture(function(ctx) diff --git a/lua/nvim-lsp-installer/servers/elmls/init.lua b/lua/nvim-lsp-installer/servers/elmls/init.lua index 30e69055..676beddd 100644 --- a/lua/nvim-lsp-installer/servers/elmls/init.lua +++ b/lua/nvim-lsp-installer/servers/elmls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/elm-tooling/elm-language-server", installer = npm.packages { "@elm-tooling/elm-language-server", "elm", "elm-test", "elm-format" }, default_options = { cmd = { npm.executable(root_dir, "elm-language-server") }, diff --git a/lua/nvim-lsp-installer/servers/ember/init.lua b/lua/nvim-lsp-installer/servers/ember/init.lua index 11b64a17..095503ef 100644 --- a/lua/nvim-lsp-installer/servers/ember/init.lua +++ b/lua/nvim-lsp-installer/servers/ember/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/lifeart/ember-language-server", installer = npm.packages { "@lifeart/ember-language-server" }, default_options = { cmd = { npm.executable(root_dir, "ember-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/emmet_ls/init.lua b/lua/nvim-lsp-installer/servers/emmet_ls/init.lua index ee5fda7a..2588bcc5 100644 --- a/lua/nvim-lsp-installer/servers/emmet_ls/init.lua +++ b/lua/nvim-lsp-installer/servers/emmet_ls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/aca/emmet-ls", installer = npm.packages { "emmet-ls" }, pre_setup = function() local lspconfig = require "lspconfig" diff --git a/lua/nvim-lsp-installer/servers/fortls/init.lua b/lua/nvim-lsp-installer/servers/fortls/init.lua index cee618e1..d9c771fb 100644 --- a/lua/nvim-lsp-installer/servers/fortls/init.lua +++ b/lua/nvim-lsp-installer/servers/fortls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/hansec/fortran-language-server", installer = pip3.packages { "fortran-language-server" }, default_options = { cmd = { pip3.executable(root_dir, "fortls") }, diff --git a/lua/nvim-lsp-installer/servers/gopls/init.lua b/lua/nvim-lsp-installer/servers/gopls/init.lua index 9534673b..26e0d45e 100644 --- a/lua/nvim-lsp-installer/servers/gopls/init.lua +++ b/lua/nvim-lsp-installer/servers/gopls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://pkg.go.dev/golang.org/x/tools/gopls", installer = go.packages { "golang.org/x/tools/gopls" }, default_options = { cmd = { go.executable(root_dir, "gopls") }, diff --git a/lua/nvim-lsp-installer/servers/graphql/init.lua b/lua/nvim-lsp-installer/servers/graphql/init.lua index d11f77ef..5be801e6 100644 --- a/lua/nvim-lsp-installer/servers/graphql/init.lua +++ b/lua/nvim-lsp-installer/servers/graphql/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://www.npmjs.com/package/graphql-language-service-cli", installer = npm.packages { "graphql-language-service-cli", "graphql" }, default_options = { cmd = { npm.executable(root_dir, "graphql-lsp"), "server", "-m", "stream" }, diff --git a/lua/nvim-lsp-installer/servers/groovyls/init.lua b/lua/nvim-lsp-installer/servers/groovyls/init.lua index 614d196b..a895f566 100644 --- a/lua/nvim-lsp-installer/servers/groovyls/init.lua +++ b/lua/nvim-lsp-installer/servers/groovyls/init.lua @@ -6,6 +6,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/GroovyLanguageServer/groovy-language-server", installer = { std.ensure_executables { { "javac", "javac was not found in path." } }, std.git_clone "https://github.com/GroovyLanguageServer/groovy-language-server", diff --git a/lua/nvim-lsp-installer/servers/hls/init.lua b/lua/nvim-lsp-installer/servers/hls/init.lua index b3197ed7..a6ad0ef4 100644 --- a/lua/nvim-lsp-installer/servers/hls/init.lua +++ b/lua/nvim-lsp-installer/servers/hls/init.lua @@ -11,6 +11,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://haskell-language-server.readthedocs.io/en/latest/", installer = { context.github_release_file("haskell/haskell-language-server", function(version) return Data.coalesce( diff --git a/lua/nvim-lsp-installer/servers/intelephense/init.lua b/lua/nvim-lsp-installer/servers/intelephense/init.lua index 835aa124..1d4ddb74 100644 --- a/lua/nvim-lsp-installer/servers/intelephense/init.lua +++ b/lua/nvim-lsp-installer/servers/intelephense/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://intelephense.com", installer = npm.packages { "intelephense" }, default_options = { cmd = { npm.executable(root_dir, "intelephense"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/jdtls/init.lua b/lua/nvim-lsp-installer/servers/jdtls/init.lua index 806babd8..2e9a88bd 100644 --- a/lua/nvim-lsp-installer/servers/jdtls/init.lua +++ b/lua/nvim-lsp-installer/servers/jdtls/init.lua @@ -42,6 +42,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/eclipse/eclipse.jdt.ls", installer = { context.capture(function(ctx) local version = ctx.requested_server_version or "latest" diff --git a/lua/nvim-lsp-installer/servers/jedi_language_server/init.lua b/lua/nvim-lsp-installer/servers/jedi_language_server/init.lua index f3d53e8c..a91b34ba 100644 --- a/lua/nvim-lsp-installer/servers/jedi_language_server/init.lua +++ b/lua/nvim-lsp-installer/servers/jedi_language_server/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/pappasam/jedi-language-server", installer = pip3.packages { "jedi-language-server" }, default_options = { cmd = { pip3.executable(root_dir, "jedi-language-server") }, diff --git a/lua/nvim-lsp-installer/servers/kotlin_language_server/init.lua b/lua/nvim-lsp-installer/servers/kotlin_language_server/init.lua index baff307f..e21766c8 100644 --- a/lua/nvim-lsp-installer/servers/kotlin_language_server/init.lua +++ b/lua/nvim-lsp-installer/servers/kotlin_language_server/init.lua @@ -8,6 +8,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/fwcd/kotlin-language-server", installer = { context.github_release_file("fwcd/kotlin-language-server", "server.zip"), context.capture(function(ctx) diff --git a/lua/nvim-lsp-installer/servers/lemminx/init.lua b/lua/nvim-lsp-installer/servers/lemminx/init.lua index b82f775c..d88a3005 100644 --- a/lua/nvim-lsp-installer/servers/lemminx/init.lua +++ b/lua/nvim-lsp-installer/servers/lemminx/init.lua @@ -18,6 +18,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/eclipse/lemminx", installer = { function(_, callback, ctx) if not unzipped_file then diff --git a/lua/nvim-lsp-installer/servers/ltex/init.lua b/lua/nvim-lsp-installer/servers/ltex/init.lua index 4bbdf69a..a1553976 100644 --- a/lua/nvim-lsp-installer/servers/ltex/init.lua +++ b/lua/nvim-lsp-installer/servers/ltex/init.lua @@ -14,6 +14,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://valentjn.github.io/vscode-ltex", installer = { context.github_release_file("valentjn/ltex-ls", function(version) return coalesce( diff --git a/lua/nvim-lsp-installer/servers/ocamlls/init.lua b/lua/nvim-lsp-installer/servers/ocamlls/init.lua index 7de21479..8fbc8dc7 100644 --- a/lua/nvim-lsp-installer/servers/ocamlls/init.lua +++ b/lua/nvim-lsp-installer/servers/ocamlls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/ocaml-lsp/ocaml-language-server", installer = npm.packages { "ocaml-language-server" }, default_options = { cmd = { npm.executable(root_dir, "ocaml-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/omnisharp/init.lua b/lua/nvim-lsp-installer/servers/omnisharp/init.lua index ae9594c0..294c1d02 100644 --- a/lua/nvim-lsp-installer/servers/omnisharp/init.lua +++ b/lua/nvim-lsp-installer/servers/omnisharp/init.lua @@ -11,6 +11,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/OmniSharp/omnisharp-roslyn", installer = { context.github_release_file( "OmniSharp/omnisharp-roslyn", diff --git a/lua/nvim-lsp-installer/servers/phpactor/init.lua b/lua/nvim-lsp-installer/servers/phpactor/init.lua index 67a84238..16823520 100644 --- a/lua/nvim-lsp-installer/servers/phpactor/init.lua +++ b/lua/nvim-lsp-installer/servers/phpactor/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://phpactor.readthedocs.io/en/master/", installer = composer.packages { "phpactor/phpactor" }, default_options = { cmd = { composer.executable(root_dir, "phpactor"), "language-server" }, diff --git a/lua/nvim-lsp-installer/servers/prismals/init.lua b/lua/nvim-lsp-installer/servers/prismals/init.lua index 4bca4a9a..97ad49d9 100644 --- a/lua/nvim-lsp-installer/servers/prismals/init.lua +++ b/lua/nvim-lsp-installer/servers/prismals/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/prisma/language-tools", installer = npm.packages { "@prisma/language-server" }, default_options = { cmd = { npm.executable(root_dir, "prisma-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/puppet/init.lua b/lua/nvim-lsp-installer/servers/puppet/init.lua index f69757c5..a1642d62 100644 --- a/lua/nvim-lsp-installer/servers/puppet/init.lua +++ b/lua/nvim-lsp-installer/servers/puppet/init.lua @@ -7,6 +7,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/puppetlabs/puppet-editor-services", installer = { context.github_release_file("puppetlabs/puppet-editor-services", function(version) return ("puppet_editor_services_%s.zip"):format(version) diff --git a/lua/nvim-lsp-installer/servers/purescriptls/init.lua b/lua/nvim-lsp-installer/servers/purescriptls/init.lua index 8d04537c..63981df0 100644 --- a/lua/nvim-lsp-installer/servers/purescriptls/init.lua +++ b/lua/nvim-lsp-installer/servers/purescriptls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/nwolverson/purescript-language-server", installer = npm.packages { "purescript-language-server" }, default_options = { cmd = { npm.executable(root_dir, "purescript-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/pylsp/init.lua b/lua/nvim-lsp-installer/servers/pylsp/init.lua index 42537411..8a14111d 100644 --- a/lua/nvim-lsp-installer/servers/pylsp/init.lua +++ b/lua/nvim-lsp-installer/servers/pylsp/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/python-lsp/python-lsp-server", installer = pip3.packages { "python-lsp-server[all]" }, default_options = { cmd = { pip3.executable(root_dir, "pylsp") }, diff --git a/lua/nvim-lsp-installer/servers/pyright/init.lua b/lua/nvim-lsp-installer/servers/pyright/init.lua index 1df23958..521830f6 100644 --- a/lua/nvim-lsp-installer/servers/pyright/init.lua +++ b/lua/nvim-lsp-installer/servers/pyright/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/microsoft/pyright", installer = npm.packages { "pyright" }, default_options = { cmd = { npm.executable(root_dir, "pyright-langserver"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/rescriptls/init.lua b/lua/nvim-lsp-installer/servers/rescriptls/init.lua index caec9d53..590eafc5 100644 --- a/lua/nvim-lsp-installer/servers/rescriptls/init.lua +++ b/lua/nvim-lsp-installer/servers/rescriptls/init.lua @@ -7,6 +7,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/rescript-lang/rescript-vscode", installer = { context.github_release_file("rescript-lang/rescript-vscode", function(version) return ("rescript-vscode-%s.vsix"):format(version) diff --git a/lua/nvim-lsp-installer/servers/rome/init.lua b/lua/nvim-lsp-installer/servers/rome/init.lua index e4e61ab7..17564b9e 100644 --- a/lua/nvim-lsp-installer/servers/rome/init.lua +++ b/lua/nvim-lsp-installer/servers/rome/init.lua @@ -7,6 +7,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://rome.tools", installer = { context.set(function(ctx) ctx.requested_server_version = Data.coalesce( diff --git a/lua/nvim-lsp-installer/servers/rust_analyzer/init.lua b/lua/nvim-lsp-installer/servers/rust_analyzer/init.lua index fc843964..7e96a54d 100644 --- a/lua/nvim-lsp-installer/servers/rust_analyzer/init.lua +++ b/lua/nvim-lsp-installer/servers/rust_analyzer/init.lua @@ -35,6 +35,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://rust-analyzer.github.io", installer = { context.github_release_file("rust-analyzer/rust-analyzer", target), context.capture(function(ctx) diff --git a/lua/nvim-lsp-installer/servers/serve_d/init.lua b/lua/nvim-lsp-installer/servers/serve_d/init.lua index 719d9d5f..f7c01bcf 100644 --- a/lua/nvim-lsp-installer/servers/serve_d/init.lua +++ b/lua/nvim-lsp-installer/servers/serve_d/init.lua @@ -9,6 +9,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/Pure-D/serve-d", installer = { context.set(function(ctx) -- Consider the latest (as of writing) beta release as "latest", instead of 0.6.0. diff --git a/lua/nvim-lsp-installer/servers/solang/init.lua b/lua/nvim-lsp-installer/servers/solang/init.lua index b1405f46..6b3fac2c 100644 --- a/lua/nvim-lsp-installer/servers/solang/init.lua +++ b/lua/nvim-lsp-installer/servers/solang/init.lua @@ -47,6 +47,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://solang.readthedocs.io/en/latest/", installer = { solang_executable_installer, llvm_installer, diff --git a/lua/nvim-lsp-installer/servers/solargraph/init.lua b/lua/nvim-lsp-installer/servers/solargraph/init.lua index 4e0e4598..9bd3afc2 100644 --- a/lua/nvim-lsp-installer/servers/solargraph/init.lua +++ b/lua/nvim-lsp-installer/servers/solargraph/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://solargraph.org", installer = gem.packages { "solargraph" }, default_options = { cmd = { gem.executable(root_dir, "solargraph"), "stdio" }, diff --git a/lua/nvim-lsp-installer/servers/sqlls/init.lua b/lua/nvim-lsp-installer/servers/sqlls/init.lua index e8ccd56e..29b0449e 100644 --- a/lua/nvim-lsp-installer/servers/sqlls/init.lua +++ b/lua/nvim-lsp-installer/servers/sqlls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/joe-re/sql-language-server", installer = npm.packages { "sql-language-server" }, default_options = { cmd = { npm.executable(root_dir, "sql-language-server") }, diff --git a/lua/nvim-lsp-installer/servers/sqls/init.lua b/lua/nvim-lsp-installer/servers/sqls/init.lua index d58e9353..5e3f4e1c 100644 --- a/lua/nvim-lsp-installer/servers/sqls/init.lua +++ b/lua/nvim-lsp-installer/servers/sqls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/lighttiger2505/sqls", installer = go.packages { "github.com/lighttiger2505/sqls" }, default_options = { cmd = { go.executable(root_dir, "sqls") }, diff --git a/lua/nvim-lsp-installer/servers/stylelint_lsp/init.lua b/lua/nvim-lsp-installer/servers/stylelint_lsp/init.lua index 113f7329..ea72db8f 100644 --- a/lua/nvim-lsp-installer/servers/stylelint_lsp/init.lua +++ b/lua/nvim-lsp-installer/servers/stylelint_lsp/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/bmatcuk/stylelint-lsp", installer = npm.packages { "stylelint-lsp" }, default_options = { cmd = { npm.executable(root_dir, "stylelint-lsp"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/sumneko_lua/init.lua b/lua/nvim-lsp-installer/servers/sumneko_lua/init.lua index 008a2e4f..19b64649 100644 --- a/lua/nvim-lsp-installer/servers/sumneko_lua/init.lua +++ b/lua/nvim-lsp-installer/servers/sumneko_lua/init.lua @@ -15,6 +15,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/sumneko/lua-language-server", installer = { context.github_release_file("sumneko/vscode-lua", function(version) return ("lua-%s.vsix"):format(version:gsub("^v", "")) diff --git a/lua/nvim-lsp-installer/servers/svelte/init.lua b/lua/nvim-lsp-installer/servers/svelte/init.lua index c94b1f89..2415de63 100644 --- a/lua/nvim-lsp-installer/servers/svelte/init.lua +++ b/lua/nvim-lsp-installer/servers/svelte/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/sveltejs/language-tools", installer = npm.packages { "svelte-language-server" }, default_options = { cmd = { npm.executable(root_dir, "svelteserver"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/terraformls/init.lua b/lua/nvim-lsp-installer/servers/terraformls/init.lua index e400e2ce..a584c940 100644 --- a/lua/nvim-lsp-installer/servers/terraformls/init.lua +++ b/lua/nvim-lsp-installer/servers/terraformls/init.lua @@ -11,6 +11,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/hashicorp/terraform-ls", installer = { context.github_release_file("hashicorp/terraform-ls", function(version) return Data.coalesce( diff --git a/lua/nvim-lsp-installer/servers/texlab/init.lua b/lua/nvim-lsp-installer/servers/texlab/init.lua index 1a38be26..425ba78a 100644 --- a/lua/nvim-lsp-installer/servers/texlab/init.lua +++ b/lua/nvim-lsp-installer/servers/texlab/init.lua @@ -11,6 +11,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/latex-lsp/texlab", installer = { std.ensure_executables { { "pdflatex", "A TeX distribution is not installed. Refer to https://www.latex-project.org/get/." }, diff --git a/lua/nvim-lsp-installer/servers/tflint/init.lua b/lua/nvim-lsp-installer/servers/tflint/init.lua index 35f00918..97f76217 100644 --- a/lua/nvim-lsp-installer/servers/tflint/init.lua +++ b/lua/nvim-lsp-installer/servers/tflint/init.lua @@ -23,6 +23,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/terraform-linters/tflint", installer = { context.github_release_file("terraform-linters/tflint", target), context.capture(function(ctx) diff --git a/lua/nvim-lsp-installer/servers/tsserver/init.lua b/lua/nvim-lsp-installer/servers/tsserver/init.lua index ec66e1c1..d4008933 100644 --- a/lua/nvim-lsp-installer/servers/tsserver/init.lua +++ b/lua/nvim-lsp-installer/servers/tsserver/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/typescript-language-server/typescript-language-server", installer = npm.packages { "typescript-language-server", "typescript" }, default_options = { cmd = { npm.executable(root_dir, "typescript-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/vimls/init.lua b/lua/nvim-lsp-installer/servers/vimls/init.lua index 756e32aa..4ea07465 100644 --- a/lua/nvim-lsp-installer/servers/vimls/init.lua +++ b/lua/nvim-lsp-installer/servers/vimls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/iamcco/vim-language-server", installer = npm.packages { "vim-language-server" }, default_options = { cmd = { npm.executable(root_dir, "vim-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/volar/init.lua b/lua/nvim-lsp-installer/servers/volar/init.lua index d7f2a44b..26af7d5d 100644 --- a/lua/nvim-lsp-installer/servers/volar/init.lua +++ b/lua/nvim-lsp-installer/servers/volar/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/johnsoncodehk/volar", installer = npm.packages { "@volar/server" }, default_options = { cmd = { npm.executable(root_dir, "volar-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/vuels/init.lua b/lua/nvim-lsp-installer/servers/vuels/init.lua index ff251e6b..d208c0a3 100644 --- a/lua/nvim-lsp-installer/servers/vuels/init.lua +++ b/lua/nvim-lsp-installer/servers/vuels/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/vlang/vls", installer = npm.packages { "vls" }, default_options = { cmd = { npm.executable(root_dir, "vls"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/yamlls/init.lua b/lua/nvim-lsp-installer/servers/yamlls/init.lua index f02d7642..ed65d03f 100644 --- a/lua/nvim-lsp-installer/servers/yamlls/init.lua +++ b/lua/nvim-lsp-installer/servers/yamlls/init.lua @@ -5,6 +5,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/redhat-developer/yaml-language-server", installer = npm.packages { "yaml-language-server" }, default_options = { cmd = { npm.executable(root_dir, "yaml-language-server"), "--stdio" }, diff --git a/lua/nvim-lsp-installer/servers/zls/init.lua b/lua/nvim-lsp-installer/servers/zls/init.lua index c9d32790..e6cd5928 100644 --- a/lua/nvim-lsp-installer/servers/zls/init.lua +++ b/lua/nvim-lsp-installer/servers/zls/init.lua @@ -20,6 +20,7 @@ return function(name, root_dir) return server.Server:new { name = name, root_dir = root_dir, + homepage = "https://github.com/zigtools/zls", installer = { context.github_release_file("zigtools/zls", ("%s.tar.xz"):format(archive_name)), context.capture(function(ctx) diff --git a/lua/nvim-lsp-installer/settings.lua b/lua/nvim-lsp-installer/settings.lua index 1d7fa283..7a61510f 100644 --- a/lua/nvim-lsp-installer/settings.lua +++ b/lua/nvim-lsp-installer/settings.lua @@ -8,6 +8,16 @@ local DEFAULT_SETTINGS = { -- The list icon to use for servers that are not installed. server_uninstalled = "◍", }, + keymaps = { + -- Keymap to expand a server in the UI + toggle_server_expand = "<CR>", + -- Keymap to install a server + install_server = "i", + -- Keymap to reinstall/update a server + update_server = "u", + -- Keymap to uninstall a server + uninstall_server = "X", + }, }, -- Controls to which degree logs are written to the log file. It's useful to set this to vim.log.levels.DEBUG when @@ -19,6 +29,10 @@ local DEFAULT_SETTINGS = { -- example, installing `cssls` will also install both `jsonls` and `html` (and the other ways around), as these all -- share the same underlying package. allow_federated_servers = true, + + -- Limit for the maximum amount of servers to be installed at the same time. Once this limit is reached, any further + -- servers that are requested to be installed will be put in a queue. + max_concurrent_installers = 4, } local M = {} diff --git a/lua/nvim-lsp-installer/ui/display.lua b/lua/nvim-lsp-installer/ui/display.lua index 27aca167..e675d715 100644 --- a/lua/nvim-lsp-installer/ui/display.lua +++ b/lua/nvim-lsp-installer/ui/display.lua @@ -3,6 +3,20 @@ local log = require "nvim-lsp-installer.log" local process = require "nvim-lsp-installer.process" local state = require "nvim-lsp-installer.ui.state" +local M = {} + +local function from_hex(str) + return (str:gsub("..", function(cc) + return string.char(tonumber(cc, 16)) + end)) +end + +local function to_hex(str) + return (str:gsub(".", function(c) + return string.format("%02X", string.byte(c)) + end)) +end + local function get_styles(line, render_context) local indentation = 0 @@ -29,11 +43,13 @@ local function render_node(context, node, _render_context, _output) context = context, applied_block_styles = {}, } - local output = _output or { - lines = {}, - virt_texts = {}, - highlights = {}, - } + local output = _output + or { + lines = {}, + virt_texts = {}, + highlights = {}, + keybinds = {}, + } if node.type == Ui.NodeType.VIRTUAL_TEXT then output.virt_texts[#output.virt_texts + 1] = { @@ -81,6 +97,13 @@ local function render_node(context, node, _render_context, _output) if node.type == Ui.NodeType.CASCADING_STYLE then render_context.applied_block_styles[#render_context.applied_block_styles] = nil end + elseif node.type == Ui.NodeType.KEYBIND_HANDLER then + output.keybinds[#output.keybinds + 1] = { + line = node.is_global and -1 or #output.lines, + key = node.key, + effect = node.effect, + payload = node.payload, + } end return output @@ -102,10 +125,35 @@ local function create_popup_window_opts() return popup_layout end -local M = {} - +local registered_effect_handlers_by_bufnr = {} +local active_keybinds_by_bufnr = {} +local registered_keymaps_by_bufnr = {} local redraw_by_win_id = {} +local function call_effect_handler(bufnr, line, key) + local line_keybinds = active_keybinds_by_bufnr[bufnr][line] + if line_keybinds then + local keybind = line_keybinds[key] + if keybind then + local effect_handler = registered_effect_handlers_by_bufnr[bufnr][keybind.effect] + if effect_handler then + log.fmt_trace("Calling handler for effect %s on line %d for key %s", keybind.effect, line, key) + effect_handler { payload = keybind.payload } + return true + end + end + end + return false +end + +M.dispatch_effect = vim.schedule_wrap(function(bufnr, hex_key) + local key = from_hex(hex_key) + local line = vim.api.nvim_win_get_cursor(0)[1] + log.fmt_trace("Dispatching effect on line %d, key %s, bufnr %s", line, key, bufnr) + call_effect_handler(bufnr, line, key) -- line keybinds + call_effect_handler(bufnr, -1, key) -- global keybinds +end) + function M.redraw_win(win_id) local fn = redraw_by_win_id[win_id] if fn then @@ -129,6 +177,15 @@ function M.delete_win_buf(win_id, bufnr) if redraw_by_win_id[win_id] then redraw_by_win_id[win_id] = nil end + if active_keybinds_by_bufnr[bufnr] then + active_keybinds_by_bufnr[bufnr] = nil + end + if registered_effect_handlers_by_bufnr[bufnr] then + registered_effect_handlers_by_bufnr[bufnr] = nil + end + if registered_keymaps_by_bufnr[bufnr] then + registered_keymaps_by_bufnr[bufnr] = nil + end end) end @@ -143,6 +200,10 @@ function M.new_view_only_win(name) bufnr = vim.api.nvim_create_buf(false, true) win_id = vim.api.nvim_open_win(bufnr, true, create_popup_window_opts()) + registered_effect_handlers_by_bufnr[bufnr] = {} + active_keybinds_by_bufnr[bufnr] = {} + registered_keymaps_by_bufnr[bufnr] = {} + local buf_opts = { modifiable = false, swapfile = false, @@ -185,8 +246,6 @@ function M.new_view_only_win(name) ):format(win_id, bufnr) ) - vim.api.nvim_buf_set_keymap(bufnr, "n", "<esc>", "<cmd>bd<CR>", { noremap = true }) - if highlight_groups then for i = 1, #highlight_groups do vim.cmd(highlight_groups[i]) @@ -214,8 +273,10 @@ function M.new_view_only_win(name) win_width = win_width, } local output = render_node(context, view) - local lines, virt_texts, highlights = output.lines, output.virt_texts, output.highlights + local lines, virt_texts, highlights, keybinds = + output.lines, output.virt_texts, output.highlights, output.keybinds + -- set line contents vim.api.nvim_buf_clear_namespace(0, namespace, 0, -1) vim.api.nvim_buf_set_option(bufnr, "modifiable", true) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) @@ -227,6 +288,8 @@ function M.new_view_only_win(name) virt_text = virt_text.content, }) end + + -- set highlights for i = 1, #highlights do local highlight = highlights[i] vim.api.nvim_buf_add_highlight( @@ -238,6 +301,32 @@ function M.new_view_only_win(name) highlight.col_end ) end + + -- set keybinds + local buf_keybinds = {} + active_keybinds_by_bufnr[bufnr] = buf_keybinds + for i = 1, #keybinds do + local keybind = keybinds[i] + if not buf_keybinds[keybind.line] then + buf_keybinds[keybind.line] = {} + end + buf_keybinds[keybind.line][keybind.key] = keybind + if not registered_keymaps_by_bufnr[bufnr][keybind.key] then + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + keybind.key, + ("<cmd>lua require('nvim-lsp-installer.ui.display').dispatch_effect(%d, %q)<cr>"):format( + bufnr, + -- We transfer the keybinding as hex to avoid issues with (neo)vim interpreting the key as a + -- literal input to the command. For example, "<CR>" would cause vim to issue an actual carriage + -- return - even if it's quoted as a string. + to_hex(keybind.key) + ), + { nowait = true, silent = true, noremap = true } + ) + end + end end) return { @@ -267,6 +356,7 @@ function M.new_view_only_win(name) unsubscribe(false) local opened_win_id = open(opts) draw(renderer(get_state())) + registered_effect_handlers_by_bufnr[bufnr] = opts.effects redraw_by_win_id[opened_win_id] = function() if vim.api.nvim_win_is_valid(opened_win_id) then draw(renderer(get_state())) @@ -274,16 +364,19 @@ function M.new_view_only_win(name) end end end), - -- This is probably not needed. - -- destroy = vim.schedule_wrap(function() - -- assert(has_initiated, "Display has not been initiated, cannot destroy.") - -- TODO: what happens with the state container, etc? - -- unsubscribe(true) - -- redraw_by_winnr[win_id] = nil - -- if win_id then - -- vim.api.nvim_win_close(win_id, true) - -- end - -- end), + close = vim.schedule_wrap(function() + assert(has_initiated, "Display has not been initiated, cannot close.") + unsubscribe(true) + M.delete_win_buf(win_id, bufnr) + end), + set_cursor = function(pos) + assert(win_id ~= nil, "Window has not been opened, cannot set cursor.") + return vim.api.nvim_win_set_cursor(win_id, pos) + end, + get_cursor = function() + assert(win_id ~= nil, "Window has not been opened, cannot get cursor.") + return vim.api.nvim_win_get_cursor(win_id) + end, } end diff --git a/lua/nvim-lsp-installer/ui/init.lua b/lua/nvim-lsp-installer/ui/init.lua index 8f5d86a6..4f8d6935 100644 --- a/lua/nvim-lsp-installer/ui/init.lua +++ b/lua/nvim-lsp-installer/ui/init.lua @@ -6,6 +6,7 @@ M.NodeType = Data.enum { "CASCADING_STYLE", "VIRTUAL_TEXT", "HL_TEXT", + "KEYBIND_HANDLER", } function M.Node(children) @@ -63,8 +64,41 @@ function M.When(condition, a) return M.Node {} end +function M.Keybind(key, effect, payload, is_global) + return { + type = M.NodeType.KEYBIND_HANDLER, + key = key, + effect = effect, + payload = payload, + is_global = is_global or false, + } +end + function M.EmptyLine() return M.Text { "" } end +function M.Table(rows) + local col_maxwidth = {} + for i = 1, #rows do + local row = rows[i] + for j = 1, #row do + local col = row[j] + local content = col[1] + col_maxwidth[j] = math.max(#content, col_maxwidth[j] or 0) + end + end + + for i = 1, #rows do + local row = rows[i] + for j = 1, #row do + local col = row[j] + local content = col[1] + col[1] = content .. string.rep(" ", (col_maxwidth[j] - #content) + 1) -- +1 for default minimum padding + end + end + + return M.HlTextNode(rows) +end + return M diff --git a/lua/nvim-lsp-installer/ui/status-win/init.lua b/lua/nvim-lsp-installer/ui/status-win/init.lua index b82aef0a..d448cd9c 100644 --- a/lua/nvim-lsp-installer/ui/status-win/init.lua +++ b/lua/nvim-lsp-installer/ui/status-win/init.lua @@ -4,6 +4,11 @@ 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 HELP_KEYMAP = "?" +local CLOSE_WINDOW_KEYMAP_1 = "<Esc>" +local CLOSE_WINDOW_KEYMAP_2 = "q" local function ServerGroupHeading(props) return Ui.HlTextNode { @@ -15,11 +20,90 @@ local function Indent(children) return Ui.CascadingStyleNode({ Ui.CascadingStyle.INDENT }, children) end +-- stylua: ignore start +local very_reasonable_cow = { + { { [[ _______________________________________________________________________ ]], "LspInstallerMuted" } }, + { { [[ < Help sponsor Neovim development! ]], "LspInstallerMuted" }, { "https://github.com/sponsors/neovim", "LspInstallerHighlighted"}, {[[ > ]], "LspInstallerMuted" } }, + { { [[ ----------------------------------------------------------------------- ]], "LspInstallerMuted" } }, + { { [[ \ ,-^-. ]], "LspInstallerMuted" } }, + { { [[ \ !oYo! ]], "LspInstallerMuted" } }, + { { [[ \ /./=\.\______ ]], "LspInstallerMuted" } }, + { { [[ ## )\/\ ]], "LspInstallerMuted" } }, + { { [[ ||-----w|| ]], "LspInstallerMuted" } }, + { { [[ || || ]], "LspInstallerMuted" } }, + { { [[ ]], "LspInstallerMuted" } }, + { { [[ Cowth Vader (alleged Neovim user) ]], "LspInstallerMuted" } }, + { { [[ ]], "LspInstallerMuted" } }, +} +-- stylua: ignore end + +local function Help(is_current_settings_expanded) + 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 }, + { "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 }, + } + + return Ui.Node { + 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", + }, + { ":help nvim-lsp-installer-debugging", "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 { + { + { + ("%s Current settings"):format(is_current_settings_expanded and "v" 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 + local function Header() return Ui.CascadingStyleNode({ Ui.CascadingStyle.CENTERED }, { Ui.HlTextNode { - { { "nvim-lsp-installer", "LspInstallerHeader" } }, - { { "https://github.com/williamboman/nvim-lsp-installer", "LspInstallerLink" } }, + { { ":help ", "LspInstallerMuted" }, { "nvim-lsp-installer", "LspInstallerHeader" } }, + { { "https://github.com/williamboman/nvim-lsp-installer", "Comment" } }, }, }) end @@ -49,26 +133,54 @@ local function get_relative_install_time(time) end end -local function InstalledServers(servers) +local function ServerMetadata(server) + return Ui.Table(Data.list_not_nil( + Data.lazy(server.metadata.install_timestamp_seconds, function() + return { + { "last updated", "LspInstallerMuted" }, + { get_relative_install_time(server.metadata.install_timestamp_seconds), "" }, + } + end), + Data.when(server.is_installed, { + { "path", "LspInstallerMuted" }, + { server.metadata.install_dir, "" }, + }), + Data.when(server.is_installed, { + { "startup command", "LspInstallerMuted" }, + { server.metadata.cmd, "" }, + }), + { + { "homepage", "LspInstallerMuted" }, + { server.metadata.homepage or "-", "" }, + } + )) +end + +local function InstalledServers(servers, expanded_server) return Ui.Node(Data.list_map(function(server) + local is_expanded = expanded_server == server.name return Ui.Node { Ui.HlTextNode { - { + Data.list_not_nil( { settings.current.ui.icons.server_installed, "LspInstallerGreen" }, - { " " .. server.name, "" }, - { - (" installed %s"):format(get_relative_install_time(server.creation_time)), - "Comment", - }, - }, + { " " .. server.name, "" } + ), }, + 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.uninstall_server, "UNINSTALL_SERVER", { server.name }), + Ui.When(is_expanded, function() + return Indent { + ServerMetadata(server), + } + end), } end, servers)) end local function TailedOutput(server) return Ui.HlTextNode(Data.list_map(function(line) - return { { line, "LspInstallerGray" } } + return { { line, "LspInstallerMuted" } } end, server.installer.tailed_output)) end @@ -85,22 +197,23 @@ end local function PendingServers(servers) return Ui.Node(Data.list_map(function(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 "(running)") + 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 "LspInstallerGray" }, + { " " .. server.name, server.installer.is_running and "" or "LspInstallerMuted" }, { " " .. note, "Comment" }, - { - has_failed and "" or (" " .. get_last_non_empty_line(server.installer.tailed_output)), + 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), @@ -114,16 +227,24 @@ local function PendingServers(servers) end, servers)) end -local function UninstalledServers(servers) +local function UninstalledServers(servers, expanded_server) return Ui.Node(Data.list_map(function(server) + local is_expanded = expanded_server == server.name return Ui.Node { Ui.HlTextNode { - { - { settings.current.ui.icons.server_uninstalled, "LspInstallerGray" }, - { " " .. server.name, "Comment" }, - { server.uninstaller.has_run and " (just uninstalled)" or "", "Comment" }, - }, + Data.list_not_nil( + { settings.current.ui.icons.server_uninstalled, "LspInstallerMuted" }, + { " " .. server.name, "LspInstallerMuted" }, + Data.when(server.uninstaller.has_run, { " (just uninstalled)", "Comment" }) + ), }, + 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 @@ -144,13 +265,13 @@ local function ServerGroup(props) count = total_server_count, }, Indent(Data.list_map(function(servers) - return props.renderer(servers) + return props.renderer(servers, props.expanded_server) end, props.servers)), } end) end -local function Servers(servers) +local function Servers(servers, expanded_server) local grouped_servers = { installed = {}, queued = {}, @@ -192,6 +313,7 @@ local function Servers(servers) title = "Installed servers", renderer = InstalledServers, servers = { grouped_servers.session_installed, grouped_servers.installed }, + expanded_server = expanded_server, }, ServerGroup { title = "Pending servers", @@ -203,26 +325,27 @@ local function Servers(servers) 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 }, + expanded_server = expanded_server, }, } end -local function create_server_state(server) - local ok, fstat = pcall(fs.fstat, server.root_dir) - local creation_time - if ok then - creation_time = fstat.mtime.sec - end - +local function create_initial_server_state(server) return { name = server.name, is_installed = server:is_installed(), - creation_time = creation_time, + metadata = { + cmd = table.concat(server._default_options.cmd, " "), + homepage = server.homepage, + install_timestamp_seconds = nil, -- lazy + install_dir = server.root_dir, + }, installer = { is_queued = false, is_running = false, @@ -246,34 +369,54 @@ local function init(all_servers) window.view(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), Header(), - Servers(state.servers), + Ui.When(state.is_showing_help, function() + return Help(state.is_current_settings_expanded) + end), + Ui.When(not state.is_showing_help, function() + return Servers(state.servers, state.expanded_server) + end), } end) local servers = {} for i = 1, #all_servers do local server = all_servers[i] - servers[server.name] = create_server_state(server) + servers[server.name] = create_initial_server_state(server) end local mutate_state, get_state = window.init { servers = servers, + is_showing_help = false, + expanded_server = nil, } - local function open() - window.open { - win_width = 95, - highlight_groups = { - "hi def LspInstallerHeader gui=bold guifg=#ebcb8b", - "hi def link LspInstallerLink Comment", - "hi def LspInstallerHeading gui=bold", - "hi def LspInstallerGreen guifg=#a3be8c", - "hi def LspInstallerOrange ctermfg=222 guifg=#ebcb8b", - "hi def LspInstallerGray guifg=#888888 ctermfg=144", - "hi def LspInstallerError ctermfg=203 guifg=#f44747", - }, - } + -- TODO: memoize or throttle.. or cache. Do something. Also, as opposed to what the naming currently suggests, this + -- is not really doing anything async stuff, but will very likely do so in the future :tm:. + local async_populate_server_metadata = vim.schedule_wrap(function(server_name) + 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 + end) + end) + + 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 local function start_install(server_tuple, on_complete) @@ -309,10 +452,10 @@ local function init(all_servers) state.servers[server.name].installer.tailed_output = {} end state.servers[server.name].is_installed = success - state.servers[server.name].creation_time = os.time() state.servers[server.name].installer.is_running = false state.servers[server.name].installer.has_run = true end) + expand_server(server.name) on_complete() end) end @@ -320,7 +463,7 @@ local function init(all_servers) -- We have a queue because installers have a tendency to hog resources. local queue do - local max_running = 2 + local max_running = settings.current.max_concurrent_installers local q = {} local r = 0 @@ -342,39 +485,101 @@ local function init(all_servers) end end - return { - open = open, - install_server = function(server, version) - log.debug("Installing server", server, version) - 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_server_state(server) - state.servers[server.name].installer.is_queued = true - end) - queue(server, version) - end, - uninstall_server = function(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 + local function install_server(server, version) + log.debug("Installing server", server, version) + 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) + queue(server, version) + end + + 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 is_uninstalled, err = pcall(server.uninstall, server) - mutate_state(function(state) - state.servers[server.name] = create_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 open() + mutate_state(function(state) + state.is_showing_help = false + end) + + window.open { + win_width = 95, + 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 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", + }, + effects = { + ["TOGGLE_HELP"] = function() + if not get_state().is_showing_help then + window.set_cursor { 1, 1 } + end + mutate_state(function(state) + state.is_showing_help = not state.is_showing_help + end) + end, + ["CLOSE_WINDOW"] = function() + window.close() + 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, + ["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, + ["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, + }, + } + end + + return { + open = open, + install_server = install_server, + uninstall_server = uninstall_server, } end @@ -383,7 +588,6 @@ return function() if win then return win end - local servers = require "nvim-lsp-installer.servers" - win = init(servers.get_available_servers()) + win = init(lsp_servers.get_available_servers()) return win end |
