Collection of functions that will help you setup Neovim's LSP client, so you can get IDE-like features with minimum effort.
Out of the box it will help you integrate nvim-cmp (an autocompletion plugin) and nvim-lspconfig (a collection of configurations for various LSP servers).
If you have any question about a feature or configuration feel free to open a new discussion in this repository. Or join the chat #lsp-zero-nvim:matrix.org.
Neovim v0.8 or greater.
If you need support for Neovim v0.7 use the branch compat-07.
If you are new to neovim and you don't have a configuration file (init.lua
) follow this step by step tutorial.
If you know how to configure neovim go to Quickstart (for the impatient).
Also consider you might not need lsp-zero.
v3.x
is the current version of lsp-zero. If you are using a previous version and wish to update, follow one of these guides.
LSP
Autocompletion
Reference and guides
This section will teach you how to create a basic configuration.
If you know your way around Neovim and how to configure it, take a look at this examples:
Use your favorite plugin manager to install this plugin and all its lua dependencies.
For a more advance config that lazy loads everything take a look at the example on this link: Lazy loading guide.
--- Uncomment these if you want to manage LSP servers from neovim
-- {'williamboman/mason.nvim'},
-- {'williamboman/mason-lspconfig.nvim'},
{'VonHeikemen/lsp-zero.nvim', branch = 'v3.x'},
{'neovim/nvim-lspconfig'},
{'hrsh7th/cmp-nvim-lsp'},
{'hrsh7th/nvim-cmp'},
{'L3MON4D3/LuaSnip'},
use {
'VonHeikemen/lsp-zero.nvim',
branch = 'v3.x',
requires = {
--- Uncomment these if you want to manage LSP servers from neovim
-- {'williamboman/mason.nvim'},
-- {'williamboman/mason-lspconfig.nvim'},
-- LSP Support
{'neovim/nvim-lspconfig'},
-- Autocompletion
{'hrsh7th/nvim-cmp'},
{'hrsh7th/cmp-nvim-lsp'},
{'L3MON4D3/LuaSnip'},
}
}
{'VonHeikemen/lsp-zero.nvim', branch = 'v3.x'};
--- Uncomment these if you want to manage LSP servers from neovim
-- {'williamboman/mason.nvim'};
-- {'williamboman/mason-lspconfig.nvim'};
-- LSP Support
{'neovim/nvim-lspconfig'};
-- Autocompletion
{'hrsh7th/nvim-cmp'};
{'hrsh7th/cmp-nvim-lsp'};
{'L3MON4D3/LuaSnip'};
" Uncomment these if you want to manage LSP servers from neovim
" Plug 'williamboman/mason.nvim'
" Plug 'williamboman/mason-lspconfig.nvim'
" LSP Support
Plug 'neovim/nvim-lspconfig'
" Autocompletion
Plug 'hrsh7th/nvim-cmp'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'L3MON4D3/LuaSnip'
Plug 'VonHeikemen/lsp-zero.nvim', {'branch': 'v3.x'}
When using vimscript you can wrap lua code in lua <<EOF ... EOF
.
" Don't copy this example
lua <<EOF
print('this an example code')
print('written in lua')
EOF
First thing you will want to do setup some default keybindings. The common convention here is to setup these keybindings only when you have a language server active in the current file. Here is the code to achieve that.
local lsp_zero = require('lsp-zero')
lsp_zero.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp_zero.default_keymaps({buffer = bufnr})
end)
Next step is to install a language server. Go to nvim-lspconfig's documentation, in the server_configuration.md file you'll find the list of LSP servers and how to install them.
Once you have a language server installed in your system, add the setup in your Neovim config. Use the module lspconfig
, like this.
require('lspconfig').lua_ls.setup({})
Here lua_ls
is the name of the language server we have installed. If you need to customize it, add your settings inside the {}
. To know more details about lspconfig use the command :help lspconfig
.
You need to setup your language servers after you require lsp-zero.
local lsp_zero = require('lsp-zero')
lsp_zero.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp_zero.default_keymaps({buffer = bufnr})
end)
---
-- Replace these language servers
-- with the ones you have installed in your system
---
require('lspconfig').lua_ls.setup({})
require('lspconfig').rust_analyzer.setup({})
If you don't need to customize the language servers you are using, you can call the function .setup_servers() with a list of server names.
lsp_zero.setup_servers({'lua_ls', 'rust_analyzer'})
If you decided to install mason.nvim and mason-lspconfig.nvim you can manage the installation of the LSP servers from inside Neovim, and then use lsp-zero to handle the configuration.
Here is a basic usage example.
local lsp_zero = require('lsp-zero')
lsp_zero.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp_zero.default_keymaps({buffer = bufnr})
end)
require('mason').setup({})
require('mason-lspconfig').setup({
ensure_installed = {},
handlers = {
lsp_zero.default_setup,
},
})
For more details about how to use mason.nvim with lsp-zero see the guide on how to integrate with mason.nvim.
If you choose to use the function .default_keymaps() you gain access to some keybindings. All of these shortcuts are bound to built-in functions, so you can get more details using the :help
command.
K
: Displays hover information about the symbol under the cursor in a floating window. See :help vim.lsp.buf.hover().
gd
: Jumps to the definition of the symbol under the cursor. See :help vim.lsp.buf.definition().
gD
: Jumps to the declaration of the symbol under the cursor. Some servers don't implement this feature. See :help vim.lsp.buf.declaration().
gi
: Lists all the implementations for the symbol under the cursor in the quickfix window. See :help vim.lsp.buf.implementation().
go
: Jumps to the definition of the type of the symbol under the cursor. See :help vim.lsp.buf.type_definition().
gr
: Lists all the references to the symbol under the cursor in the quickfix window. See :help vim.lsp.buf.references().
gs
: Displays signature information about the symbol under the cursor in a floating window. See :help vim.lsp.buf.signature_help(). If a mapping already exists for this key this function is not bound.
<F2>
: Renames all references to the symbol under the cursor. See :help vim.lsp.buf.rename().
<F3>
: Format code in current buffer. See :help vim.lsp.buf.format().
<F4>
: Selects a code action available at the current cursor position. See :help vim.lsp.buf.code_action().
gl
: Show diagnostics in a floating window. See :help vim.diagnostic.open_float().
[d
: Move to the previous diagnostic in the current buffer. See :help vim.diagnostic.goto_prev().
]d
: Move to the next diagnostic. See :help vim.diagnostic.goto_next().
By default lsp-zero will not create a keybinding if its "taken". This means if you already use one of these in your config, or some other plugins uses it (which-key might be one), then lsp-zero's bindings will not work.
You can force lsp-zero's bindings by adding preserve_mappings = false
to .default_keymaps().
lsp_zero.on_attach(function(client, bufnr)
lsp_zero.default_keymaps({
buffer = bufnr,
preserve_mappings = false
})
end)
If you are having problems with a language server I recommend that you reduce your config to a minimal and check the logs of the LSP server.
What do I mean with a minimal example? Configure the language just using lspconfig
and increase the log level. Here is a minimal config using tsserver
as an example.
vim.lsp.set_log_level('debug')
vim.g.lsp_zero_extend_cmp = 0
vim.g.lsp_zero_extend_lspconfig = 0
local lsp_zero = require('lsp-zero.api')
local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities()
require('lspconfig').tsserver.setup({
capabilities = lsp_capabilities,
on_attach = function(client, bufnr)
lsp_zero.default_keymaps({buffer = bufnr})
end,
})
local cmp = require('cmp')
cmp.setup({
sources = {
{name = 'nvim_lsp'}
},
mapping = cmp.mapping.preset.insert({
['<C-Space>'] = cmp.mapping.complete(),
}),
snippet = {
expand = function(args)
require('luasnip').lsp_expand(args.body)
end,
},
})
Then you can test the language and inspect the log file using the command :LspLog
.
The plugin responsable for autocompletion is nvim-cmp. The default config in lsp-zero will only add the minimum required to integrate lspconfig, nvim-cmp and luasnip.
The default keybindings in lsp-zero are meant to emulate Neovim's default whenever possible.
<Ctrl-y>
: Confirms selection.
<Ctrl-e>
: Cancel completion.
<Down>
: Navigate to the next item on the list.
<Up>
: Navigate to previous item on the list.
<Ctrl-n>
: If the completion menu is visible, go to the next item. Else, trigger completion menu.
<Ctrl-p>
: If the completion menu is visible, go to the previous item. Else, trigger completion menu.
To add more keybindings I recommend you use nvim-cmp directly.
Here is an example configuration.
local cmp = require('cmp')
local cmp_action = require('lsp-zero').cmp_action()
cmp.setup({
mapping = cmp.mapping.preset.insert({
-- `Enter` key to confirm completion
['<CR>'] = cmp.mapping.confirm({select = false}),
-- Ctrl+Space to trigger completion menu
['<C-Space>'] = cmp.mapping.complete(),
-- Navigate between snippet placeholder
['<C-f>'] = cmp_action.luasnip_jump_forward(),
['<C-b>'] = cmp_action.luasnip_jump_backward(),
-- Scroll up and down in the completion documentation
['<C-u>'] = cmp.mapping.scroll_docs(-4),
['<C-d>'] = cmp.mapping.scroll_docs(4),
})
})
Changed/Removed features from the v2.x
branch.
Note: You can disable the warnings about removed functions by setting the global variable lsp_zero_api_warnings
to 0
. Before you require the module lsp-zero, put this vim.g.lsp_zero_api_warnings = 0
.
cmp
module to customize nvim-cmp.cmp
module.mason-lspconfig
to install LSP servers.lsp-zero has a function that will configure the lua language server for you: .nvim_lua_ls()
Yes, you can. You can find the details in the autocomplete documentation: Enter key to confirm completion.
If you have this problem I assume you are migrating from the v1.x
branch. What you have to do is add the luasnip source in nvim-cmp, then call the correct luasnip loader. You can find more details of this in the documentation for autocompletion.
If you find this tool useful and want to support my efforts, buy me a coffee ☕.