Skip to content
This repository has been archived by the owner on Nov 12, 2022. It is now read-only.

Commit

Permalink
feat: integrate with lspconfig's on_setup hook
Browse files Browse the repository at this point in the history
  • Loading branch information
williamboman committed Apr 27, 2022
1 parent 36b4467 commit b9a87a6
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 109 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ NVIM_HEADLESS:=nvim --headless --noplugin -u tests/minimal_init.vim

dependencies:
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim dependencies/pack/vendor/start/plenary.nvim
git clone --depth 1 https://github.com/neovim/nvim-lspconfig dependencies/pack/vendor/start/nvim-lspconfig

.PHONY: clean_dependencies
clean_dependencies:
Expand Down
80 changes: 26 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,32 @@
- [About](#about)
- [Screenshots](#screenshots)
- [Installation](#installation)
- [Packer](#packer)
- [vim-plug](#vim-plug)
- [Usage](#usage)
- [Commands](#commands)
- [Setup](#setup)
- [Commands](#commands)
- [Configuration](#configuration)
- [Available LSPs](#available-lsps)
- [Custom servers](#custom-servers)
- [Logo](#logo)
- [Roadmap](#roadmap)
- [Default configuration](#default-configuration)

## About

Neovim plugin that allows you to seamlessly install LSP servers locally (inside `:echo stdpath("data")`).
Neovim plugin that allows you to manage LSP servers (servers are installed inside `:echo stdpath("data")` by default).
It registers a hook with [`lspconfig`](https://github.com/neovim/nvim-lspconfig) that enhances the `PATH` environment,
allowing neovim's LSP client to locate the installed server executable<sup>1</sup>.

On top of just providing commands for installing & uninstalling LSP servers, it:

- provides a graphical UI
- is optimized for blazing fast startup times
- provides the ability to check for new server versions
- provides the ability to check for, and upgrade to, new server versions through a single interface
- supports installing custom versions of LSP servers (for example `:LspInstall rust_analyzer@nightly`)
- relaxes the minimum requirements by attempting multiple different utilities (for example, only one of `wget`, `curl`, or `Invoke-WebRequest` is required for HTTP requests)
- allows you to install and setup servers without having to restart neovim
- hosts [a suite of system tests](https://github.com/williamboman/nvim-lspconfig-test) for all supported servers
- has full support for Windows <img src="https://user-images.githubusercontent.com/6705160/131256603-cacf7f66-dfa9-4515-8ae4-0e42d08cfc6a.png" height="20">

<sup>1 - some servers don't provide an executable, in which case the full command to spawn the server is provided instead</sup>

## Screenshots

| | | |
Expand Down Expand Up @@ -83,6 +82,17 @@ Plug 'williamboman/nvim-lsp-installer'

## Usage

### Setup

In order for nvim-lsp-installer to register the necessary hooks at the right moment, **make sure you call the `.setup()`
function before you set up any servers with `lspconfig`**!

```lua
require("nvim-lsp-installer").setup {}
```

Refer to the [Configuration](#configuration) section for information about which settings are available.

### Commands

- `:LspInstallInfo` - opens a graphical overview of your language servers
Expand All @@ -92,54 +102,16 @@ Plug 'williamboman/nvim-lsp-installer'
- `:LspInstallLog` - opens the log file in a new tab window
- `:LspPrintInstalled` - prints all installed language servers

### Setup

The recommended way of setting up your installed servers is to do it through nvim-lsp-installer.
By doing so, nvim-lsp-installer will make sure to inject any necessary properties before calling lspconfig's setup
function for you. You may find a minimal example below. To see how you can override the default settings for a server,
refer to the [Wiki][overriding-default-settings].

Make sure you don't also set up your servers directly via lspconfig (e.g. `require("lspconfig").clangd.setup {}`), as
this will cause servers to be set up twice!

[overriding-default-settings]: https://github.com/williamboman/nvim-lsp-installer/wiki/Advanced-Configuration#overriding-the-default-lsp-server-options

```lua
local lsp_installer = require("nvim-lsp-installer")

-- Register a handler that will be called for each installed server when it's ready (i.e. when installation is finished
-- or if the server is already installed).
lsp_installer.on_server_ready(function(server)
local opts = {}

-- (optional) Customize the options passed to the server
-- if server.name == "tsserver" then
-- opts.root_dir = function() ... end
-- end

-- This setup() function will take the provided server configuration and decorate it with the necessary properties
-- before passing it onwards to lspconfig.
-- Refer to https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
server:setup(opts)
end)
```

For more advanced use cases you may also interact with more APIs nvim-lsp-installer has to offer, refer to `:help nvim-lsp-installer` for more docs.

### Configuration

You can configure certain behavior of nvim-lsp-installer by calling the `.settings()` function.

_Make sure to provide your settings before any other interactions with nvim-lsp-installer!_
You may optionally configure certain behavior of nvim-lsp-installer when calling the `.setup()` function.

Refer to the [default configuration](#default-configuration) for all available settings.

Example:

```lua
local lsp_installer = require("nvim-lsp-installer")

lsp_installer.settings({
require("nvim-lsp-installer").setup({
ui = {
icons = {
server_installed = "",
Expand Down Expand Up @@ -289,10 +261,6 @@ You can create your own installers by using the same APIs nvim-lsp-installer its

Illustrations in the logo are derived from [@Kaligule](https://schauderbasis.de/)'s "Robots" collection.

## Roadmap

- Command (and corresponding Lua API) to update outdated servers (e.g., `:LspUpdateAll`)

## Default configuration

```lua
Expand All @@ -309,12 +277,16 @@ local DEFAULT_SETTINGS = {
keymaps = {
-- Keymap to expand a server in the UI
toggle_server_expand = "<CR>",
-- Keymap to install a server
-- Keymap to install the server under the current cursor position
install_server = "i",
-- Keymap to reinstall/update a server
-- Keymap to reinstall/update the server under the current cursor position
update_server = "u",
-- Keymap to check for new version for the server under the current cursor position
check_server_version = "c",
-- Keymap to update all installed servers
update_all_servers = "U",
-- Keymap to check which installed servers are outdated
check_outdated_servers = "C",
-- Keymap to uninstall a server
uninstall_server = "X",
},
Expand Down
66 changes: 22 additions & 44 deletions doc/nvim-lsp-installer.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ it:
- relaxes the minimum requirements by attempting multiple different
utilities (for example, only one of `wget`, `curl`, or `Invoke-WebRequest`
is required for HTTP requests)
- allows you to install and setup servers without having to restart neovim
- hosts a suite of system tests for all supported servers
- has full support for Windows

Expand Down Expand Up @@ -49,6 +48,8 @@ https://github.com/williamboman/nvim-lsp-installer/blob/main/CUSTOM_SERVERS.md.
==============================================================================
QUICK START *nvim-lsp-installer-quickstart*

No custom configuration is needed to use nvim-lsp-installer.

To view the UI for nvim-lsp-installer, run: >
:LspInstallInfo
Expand Down Expand Up @@ -79,30 +80,6 @@ buffer, simply just run: >
Please refer to each server's own release page to find which versions are
available.

Then, somewhere in your initialization script (see `:h init.lua`): >
-- Register a handler that will be called for each installed server when it's ready (i.e. when installation is finished
-- or if the server is already installed).
lsp_installer.on_server_ready(function(server)
local opts = {}
-- (optional) Customize the options passed to the server
-- if server.name == "tsserver" then
-- opts.root_dir = function() ... end
-- end
-- This setup() function will take the provided server configuration and decorate it with the necessary properties
-- before passing it onwards to lspconfig.
-- Refer to https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
server:setup(opts)
end)
<

Make sure you don't also set up your servers directly via lspconfig (e.g.
`require("lspconfig").clangd.setup {}`), as this will cause servers to be set
up twice!


==============================================================================
COMMANDS *nvim-lsp-installer-commands*

Expand Down Expand Up @@ -156,20 +133,14 @@ Prints all installed language servers.
==============================================================================
SETTINGS *nvim-lsp-installer-settings*

You can configure certain behavior of nvim-lsp-installer by calling the
`.settings()` function.

Make sure to provide your settings before any other interactions with
nvim-lsp-installer!
You can configure certain behavior of nvim-lsp-installer when calling the
`.setup()` function.

Refer to the |nvim-lsp-installer-default-settings| for all available settings.

Example: >
local lsp_installer = require("nvim-lsp-installer")
-- Provide settings first!
lsp_installer.settings({
require("nvim-lsp-installer").setup({
ui = {
icons = {
server_installed = "✓",
Expand All @@ -178,10 +149,6 @@ Example: >
}
}
})
lsp_installer.on_server_ready(function (server)
server:setup {}
end)
<
*nvim-lsp-installer-default-settings*

Expand All @@ -200,12 +167,16 @@ The following settings are applied by default. >
keymaps = {
-- Keymap to expand a server in the UI
toggle_server_expand = "<CR>",
-- Keymap to install a server
-- Keymap to install the server under the current cursor position
install_server = "i",
-- Keymap to reinstall/update a server
-- Keymap to reinstall/update the server under the current cursor position
update_server = "u",
-- Keymap to check for new version for the server under the current cursor position
check_server_version = "c",
-- Keymap to update all installed servers
update_all_servers = "U",
-- Keymap to check which installed servers are outdated
check_outdated_servers = "C",
-- Keymap to uninstall a server
uninstall_server = "X",
},
Expand Down Expand Up @@ -238,7 +209,9 @@ DEBUGGING *nvim-lsp-installer-debugging*
To help with debugging issues with installing/uninstall servers, please make
sure to set nvim-lsp-installer's log level to DEBUG or TRACE, like so: >
:lua require("nvim-lsp-installer").settings({ log_level = vim.log.levels.DEBUG })
require("nvim-lsp-installer").setup {
log_level = vim.log.levels.DEBUG
}
<

You may find the logs by entering the command `:LspInstallLog`. Providing the
Expand All @@ -247,6 +220,11 @@ contents of this file when reporting an issue will help tremendously.
==============================================================================
Lua module: nvim-lsp-installer

*nvim-lsp-installer.setup()*
setup({config})
Sets up nvim-lsp-installer with the provided {config} (see
|nvim-lsp-installer-settings|).

*nvim-lsp-installer.install()*
install({server_name})
Installs the provided {server_name}. If {server_name} is already
Expand Down Expand Up @@ -345,7 +323,7 @@ class: Server
servers.

Methods: ~
- setup({opts})
- setup({opts}) *DEPRECATED - setup servers directly via lspconfig instead*
Sets up the language server and attaches all open buffers.

See:
Expand All @@ -356,7 +334,7 @@ class: Server
{opts} (table) The lspconfig server configuration.
See https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md

- setup_lsp({opts})
- setup_lsp({opts}) *DEPRECATED - setup servers directly via lspconfig instead*
Sets up the language server via lspconfig.
This function has the same signature as the setup function
in nvim-lspconfig.
Expand All @@ -365,7 +343,7 @@ class: Server
{opts} (table) The lspconfig server configuration.
See https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md

- attach_buffers()
- attach_buffers() *DEPRECATED - setup servers directly via lspconfig instead*
Attaches this server to all current open buffers with a
'filetype' that matches the server's configured filetypes.

Expand Down
6 changes: 6 additions & 0 deletions lua/nvim-lsp-installer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ local M = {}

M.settings = settings.set

---@param config table
function M.setup(config)
settings.set(config)
require("nvim-lsp-installer.middleware").register_lspconfig_hook()
end

M.info_window = {
---Opens the status window.
open = function()
Expand Down
32 changes: 32 additions & 0 deletions lua/nvim-lsp-installer/middleware.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
local util = require "lspconfig.util"
local servers = require "nvim-lsp-installer.servers"

local M = {}

---@param t1 table
---@param t2 table
local function merge_in_place(t1, t2)
for k, v in pairs(t2) do
if type(v) == "table" then
if type(t1[k]) == "table" and not vim.tbl_islist(t1[k]) then
merge_in_place(t1[k], v)
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end

function M.register_lspconfig_hook()
util.on_setup = util.add_hook_before(util.on_setup, function(config)
local ok, server = servers.get_server(config.name)
if ok then
merge_in_place(config, server._default_options)
end
end)
end

return M
39 changes: 39 additions & 0 deletions tests/middleware_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
local util = require "lspconfig.util"
local servers = require "nvim-lsp-installer.servers"
local middleware = require "nvim-lsp-installer.middleware"

describe("middleware", function()
it("should register on_setup hook with lspconfig", function()
-- 1. setup dummy server
local default_options = {
cmd = { "dummy-lsp" },
cmd_env = { PATH = "/keep/my/path/out/your/f/mouth" },
}
local server = ServerGenerator {
name = "dummy",
default_options = default_options,
}
servers.register(server)

-- 2. register hook
middleware.register_lspconfig_hook()

-- 3. call lspconfig hook
local config = {
name = "dummy",
cmd = { "should", "be", "overwritten" },
custom = "setting",
cmd_env = { SOME_DEFAULT_ENV = "important" },
}
util.on_setup(config)
assert.are.same({
cmd = { "dummy-lsp" },
name = "dummy",
custom = "setting",
cmd_env = {
PATH = "/keep/my/path/out/your/f/mouth",
SOME_DEFAULT_ENV = "important",
},
}, config)
end)
end)
Loading

0 comments on commit b9a87a6

Please sign in to comment.