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.
Hello, there. This is the new branch for version 2 of lsp-zero. This new version requires Neovim v0.8 or greater. If you need support for Neovim v0.7 or lower use the v1.x branch.
If you are here to look at the documentation and you installed lsp-zero before March 30th
, the docs you are looking for are in the v1.x branch.
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
- 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 inlay-hints.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
- Setup with clangd_extensions.nvim
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
{ -- Optional
'williamboman/mason.nvim',
build = function()
pcall(vim.cmd, 'MasonUpdate')
end,
},
{'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
{ -- Optional
'williamboman/mason.nvim',
run = function()
pcall(vim.cmd, 'MasonUpdate')
end,
},
{'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
{ -- Optional
'williamboman/mason.nvim',
run = function()
pcall(vim.cmd, 'MasonUpdate')
end,
};
{'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', {'do': ':MasonUpdate'} " 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)
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)
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()
If you check the introduction in the LSP documentation you'll find a quick explanation of what lsp-zero is doing to setup your LSP servers. TL;DR is nothing special.
If you still want to rule out (or confirm) lsp-zero as the source of whatever issue you have, use a minimal configuration. Delete or comment out your original config. Then make a new one with just the functions you need.
Here is an example with a manual setup of tsserver
.
require('mason').setup()
require('mason-lspconfig').setup()
local lsp = require('lsp-zero')
lsp.extend_cmp()
require('lspconfig').tsserver.setup({
on_attach = function(client, bufnr)
lsp.default_keymaps({buffer = bufnr})
end
})
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().
lsp.default_keymaps({
buffer = bufnr,
preserve_mappings = false
})
The plugin responsable 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)
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(),
}
})
In nvim-cmp a "source" is a neovim plugin that provides the actual data displayed in the completion menu.
Here is a list of sources you might want to configure (and install) to get a better experience.
-
cmp-buffer: provides suggestions based on the current file.
-
cmp-path: gives completions based on the filesystem.
-
cmp_luasnip: it shows snippets loaded by luasnip in the suggestions. This is useful when you install an external collection of snippets like friendly-snippets (See autocomplete docs for more details).
-
cmp-nvim-lsp: show data sent by the language server.
Quick note: when you configure the source
option in nvim-cmp the previous config will be overriden. This means that is if you use it you need to add the source for LSP again.
local lsp = require('lsp-zero').preset({})
lsp.on_attach(function(client, bufnr)
lsp.default_keymaps({buffer = bufnr})
end)
lsp.setup()
-- For this to work you need to install these plugins:
-- hrsh7th/cmp-path
-- hrsh7th/cmp-nvim-lsp
-- hrsh7th/cmp-buffer
-- saadparwaiz1/cmp_luasnip
-- rafamadriz/friendly-snippets
local cmp = require('cmp')
local cmp_action = require('lsp-zero').cmp_action()
require('luasnip.loaders.from_vscode').lazy_load()
cmp.setup({
sources = {
{name = 'path'},
{name = 'nvim_lsp'},
{name = 'buffer', keyword_length = 3},
{name = 'luasnip', keyword_length = 2},
},
mapping = {
['<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 case I feel forced to created a v3.x
branch.
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. - .extend_lspconfig() will be removed.
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 ☕.