The purpose of this plugin is to bundle all the "boilerplate code" necessary to have nvim-cmp (a popular autocompletion plugin) and nvim-lspconfig working together. And if you opt in, it can use mason.nvim to let you install language servers from inside neovim.
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.
lsp-zero version 3 is now available, the branch v3.x
has been created. Note that v2.x
is still the default, so the documentation here is still from version 2. v3.x
will become the default on september 20
.
If you are using v2.x and wish to upgrade, read this:
First, make sure you have Neovim v0.8 or greater. If you are using Neovim v0.7.2 or lower you will need to download lsp-zero v1.x.
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.
-
LSP
- Introduction
- Commands
- Creating new keybindings
- Disable keybindings
- Install new language servers
- Configure language servers
- Disable semantic highlights
- Disable a language server
- Custom servers
- Enable Format on save
- Format buffer using a keybinding
- Troubleshooting
- Diagnostics (a.k.a. error messages, warnings, etc.)
- Use icons in the sign column
- Language servers and mason.nvim
-
Autocompletion
- Introduction
- Preset settings
- Recommended sources
- Keybindings
- Use Enter to confirm completion
- Adding a source
- Add an external collection of snippets
- Preselect first item
- Basic completions for Neovim's lua api
- Enable "Super Tab"
- Regular tab complete
- Invoke completion menu manually
- Adding borders to completion menu
- Change formatting of completion item
- lsp-kind
-
Reference and guides
- API Reference
- Tutorial: Step by step setup from scratch
- Migrate from v1.x branch
- lsp-zero under the hood
- You might not need lsp-zero
- Lazy loading with lazy.nvim
- Integrate with null-ls
- Enable folds with nvim-ufo
- Enable inlay hints with lsp-inlayhints.nvim
- Setup copilot.lua + nvim-cmp
- Setup with nvim-navic
- Setup with rust-tools
- Setup with typescript.nvim
- Setup with flutter-tools
- Setup with nvim-jdtls
- Setup with nvim-metals
- Setup with haskell-tools
This section will teach you how to create a basic configuration for autocompletion and the LSP client.
If you know your way around neovim and how to configure it, take a look at this examples:
I suggest you read the requirements of mason.nvim.
Make sure you have at least the minimum requirements listed in unix systems
or windows
.
Use your favorite plugin manager to install this plugin and all its lua dependencies.
Expand lazy.nvim snippet:
{
'VonHeikemen/lsp-zero.nvim',
branch = 'v2.x',
dependencies = {
-- LSP Support
{'neovim/nvim-lspconfig'}, -- Required
{'williamboman/mason.nvim'}, -- Optional
{'williamboman/mason-lspconfig.nvim'}, -- Optional
-- Autocompletion
{'hrsh7th/nvim-cmp'}, -- Required
{'hrsh7th/cmp-nvim-lsp'}, -- Required
{'L3MON4D3/LuaSnip'}, -- Required
}
}
Expand packer.nvim snippet:
use {
'VonHeikemen/lsp-zero.nvim',
branch = 'v2.x',
requires = {
-- LSP Support
{'neovim/nvim-lspconfig'}, -- Required
{'williamboman/mason.nvim'}, -- Optional
{'williamboman/mason-lspconfig.nvim'}, -- Optional
-- Autocompletion
{'hrsh7th/nvim-cmp'}, -- Required
{'hrsh7th/cmp-nvim-lsp'}, -- Required
{'L3MON4D3/LuaSnip'}, -- Required
}
}
Expand paq.nvim snippet:
{'VonHeikemen/lsp-zero.nvim', branch = 'v2.x'};
-- LSP Support
{'neovim/nvim-lspconfig'}; -- Required
{'williamboman/mason.nvim'}; -- Optional
{'williamboman/mason-lspconfig.nvim'}; -- Optional
-- Autocompletion
{'hrsh7th/nvim-cmp'}; -- Required
{'hrsh7th/cmp-nvim-lsp'}; -- Required
{'L3MON4D3/LuaSnip'}; -- Required
Expand vim-plug snippet:
" LSP Support
Plug 'neovim/nvim-lspconfig' " Required
Plug 'williamboman/mason.nvim', " Optional
Plug 'williamboman/mason-lspconfig.nvim' " Optional
" Autocompletion
Plug 'hrsh7th/nvim-cmp' " Required
Plug 'hrsh7th/cmp-nvim-lsp' " Required
Plug 'L3MON4D3/LuaSnip' " Required
Plug 'VonHeikemen/lsp-zero.nvim', {'branch': 'v2.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
Inside your configuration file add this piece of lua code.
local lsp = require('lsp-zero').preset({})
lsp.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp.default_keymaps({buffer = bufnr})
end)
-- (Optional) Configure lua language server for neovim
require('lspconfig').lua_ls.setup(lsp.nvim_lua_ls())
lsp.setup()
If you want to install a language server for a particular file type use the command :LspInstall
. And when the installation is done restart neovim.
If you don't install mason.nvim
then you'll need to list the LSP servers you have installed using .setup_servers().
Note: if you use NixOS don't install mason.nvim
local lsp = require('lsp-zero').preset({})
lsp.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp.default_keymaps({buffer = bufnr})
end)
-- When you don't have mason.nvim installed
-- You'll need to list the servers installed in your system
lsp.setup_servers({'tsserver', 'eslint'})
-- (Optional) Configure lua language server for neovim
require('lspconfig').lua_ls.setup(lsp.nvim_lua_ls())
lsp.setup()
Here are some things you need to know:
- The configuration for the language servers are provided by nvim-lspconfig.
- lsp-zero will create keybindings, commands, and will integrate nvim-cmp (the autocompletion plugin) with lspconfig if possible. You need to require lsp-zero before lspconfig for this to work.
- Even though lsp-zero calls mason.nvim under the hood it only configures LSP servers. Other tools like formatters, linters or debuggers are not configured by lsp-zero.
- If you need to configure a language server use
lspconfig
.
When a language server gets attached to a buffer you gain access to some keybindings and commands. 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().
local lsp = require('lsp-zero').preset({})
lsp.on_attach(function(client, bufnr)
lsp.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 minimal? Configure the language server using just lspconfig
and increase the log level. Then you can test the language server and inspect the log file using the command :LspLog
.
Here is an example test with tsserver
.
vim.lsp.set_log_level('debug')
local lsp_zero = require('lsp-zero')
local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities()
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,
},
})
require('lspconfig').tsserver.setup({
capabilities = lsp_capabilities,
on_attach = function(client, bufnr)
lsp_zero.default_keymaps({buffer = bufnr})
end,
})
The plugin responsible for autocompletion is nvim-cmp. The default preset (which is called minimal) 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. -
<Ctrl-d>
: Scroll down the documentation window. -
<Ctrl-u>
: Scroll up the documentation window.
To add more keybindings I recommend you use nvim-cmp directly.
Here is an example configuration.
local lsp = require('lsp-zero').preset({})
lsp.on_attach(function(client, bufnr)
-- see :help lsp-zero-keybindings
-- to learn the available actions
lsp.default_keymaps({buffer = bufnr})
end)
lsp.setup()
-- You need to setup `cmp` after lsp-zero
local cmp = require('cmp')
local cmp_action = require('lsp-zero').cmp_action()
cmp.setup({
mapping = {
-- `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(),
}
})
sign_icons
was removed. If you want the icons you can configure them using .set_sign_icons().force_setup
option of .configure() was removed. lsp-zero will configure the server even if is not installed.force
option of .setup_servers() was removed. lsp-zero will configure all the servers listed even if they are not installed.- The preset
per-project
was removed in favor of the function .store_config(). suggest_lsp_servers
was removed. The suggestions are still available (they are a feature of mason-lspconfig), they can be triggered manually using the command:LspInstall
.cmp_capabilities
was removed. The features it enables will be configured automatically if cmp-nvim-lsp is installed.- luasnip loaders need to be called manually by the user. See luasnip documention for details. If you are using
friendly-snippets
you'll want to add the one that says "from_vscode". In the autocomplete documentation you can find an example configuration.
Settings and functions that will change in the new v3.x
branch.
Version 3 will become the default branch on September 20, 2023
.
I would like to get rid of named preset in the future. It's better if you use the default preset, the minimal. I would advice against using the one called "recommended". Just add your settings using the .preset() function.
set_lsp_keymaps
will be removed in favor of .default_keymaps().manage_nvim_cmp
will be removed in favor of .extend_cmp().setup_servers_on_start
will be removed. LSP servers will need to be listed explicitly using .setup_servers().call_servers
will be removed in favor of a explicit setup.configure_diagnostics
will be removed.
- .set_preferences() will be removed in favor of overriding option directly in .preset.
- .setup_nvim_cmp() will be removed. Use the
cmp
module to customize nvim-cmp. - .setup_servers() will no longer take an options argument. It'll only be a convenient way to initialize a list of servers.
- .default.diagnostics() will be removed. Diagnostic config has been reduced, only
severity_sort
and borders are enabled. There is no need for this anymore. - .defaults.cmp_sources() will be removed. Sources for nvim-cmp will be handled by the user.
- .defaults.cmp_mappings() will be removed. In the future only the defaults that align with Neovim's behavior will be configured. lsp-zero default functions for nvim-cmp will have to be added manually by the user.
- .nvim_workspace() will be removed. Use .nvim_lua_ls() to get the config and then use .configure() to setup the server.
- .defaults.nvim_workspace() will be replaced by .nvim_lua_ls().
- .ensure_installed() will be removed. Use the module
mason-lspconfig
to install LSP servers. - .setup() will be removed.
- .new_server() will be renamed to
.new_client()
.
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 ☕.