Lua API
setup()
The one that coordinates the call to other setup functions. Handles the configuration for nvim-cmp
and the language servers during startup. It is meant to be the last function you call.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.setup()
preset(opts)
It creates a combination of settings safe to use for specific cases.
{opts}
can be a string with one of these values:
If you want to override a setting from a preset use a lua table. Like this.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = {preserve_mappings = true, omit = {'K', 'gl'}},
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
Available presets
Presets are a combinations of options that determine how .setup() will behave, they can enable or disable features.
recommended
- Setup every language server installed with mason.nvim at startup.
- Suggest to install a language server when you encounter a new filetype.
- Setup nvim-cmp with some default completion sources, this includes support for LSP based completion.
- Setup some default keybindings for nvim-cmp.
- Show diagnostic info with "nice" icons.
- Diagnostic messages are shown in a floating window.
- Setup some keybindings related to LSP actions, things like go to definition or rename variable.
minimal
It enables the automatic setup of language servers and the configuration of diagnostics. It doesn't create keybindings for LSP. It doesn't handle the setup for nvim-cmp.
lsp-compe
Is the same as the recommended except that it assumes you want full control over the configuration for nvim-cmp. It'll provide the "client capabilities" config to the languages server but the rest of the config is controlled by the user.
lsp-only
Is the same as the recommended without any support for nvim-cmp.
manual-setup
Is the same as recommended, but without automatic setup for language servers. Suggestions for language server will be disabled. The user will need to call the functions .setup_servers() or .configure() in order to initialize the language servers.
per-project
Very similar to manual-setup. Automatic setup for language servers and suggestions are disabled. The user can setup default options for each server using .setup_servers() or .configure(). In order to initialize the server the user will need to call the .use() function.
system-lsp
Is the same as manual-setup, automatic setup for language servers and suggestions are going to be disabled. It is designed to call language servers installed "globally" on the system. The user will need to call .setup_servers() or .configure() in order to initialize the language servers.
Preset settings
suggest_lsp_servers
Enables the suggestions of lsp servers when you enter a filetype for the first time.
setup_servers_on_start
When set to true
all installed servers will be initialized on startup. When is set to the string "per-project"
only the servers listed with the function .use() will be initialized. If the value is false
servers will be initialized when you call .configure() or .setup_servers().
set_lsp_keymaps
Add keybindings to a buffer with a language server attached. You can configure the behavior using the options preserve_mappings
and omit
. If you enable preserve_mappings
lsp-zero will not override your existing keybindings. Using omit
you can specify a list of keybindings you don't want to override.
configure_diagnostics
Uses the built-in function vim.diagnostic.config to setup the way error messages are shown in the buffer. It also creates keymaps to navigate between the location of these errors.
cmp_capabilities
Tells the language servers what capabilities nvim-cmp supports.
manage_nvim_cmp
Use the default setup for nvim-cmp. It configures keybindings and completion sources for nvim-cmp.
manage_luasnip
Use the default setup for luasnip.
call_servers
If set to 'local'
it'll try to initialize servers that where installed using mason.nvim. If set to 'global'
all language servers you list using .configure() or .setup_servers() are assumed to be installed (a warning message will show up if they aren't).
sign_icons
They are shown in the "gutter" on the line diagnostics messages are located.
setup_nvim_cmp(opts)
{opts}
is a table that will allow you to override defaults configured by lsp-zero:
completion
: Configures the behavior of the completion menu. You can find more details about its properties if you start typing the command:help cmp-config.completion
.sources
: List of configurations for "data sources". See:help cmp-config.sources
to know more.documentation
: Modifies the look of the documentation window. You can find more details about its properities if you start typing the command:help cmp-config.window
.preselect
: By default, the first item in the completion menu is preselected. Disable this behaviour by setting this tocmp.PreselectMode.None
.formatting
: Modifies the look of the completion menu. You can find more details about its properities if you start typing the command:help cmp-config.formatting
.mapping
: Sets the keybindings. See:help cmp-mapping
.select_behavior
: Configure behavior when navigating between items in the completion menu. It can be set to the values'insert'
or'select'
. With the value 'select' nothing happens when you move between items. With the value 'insert' it'll put the text from the selection in the buffer. Is worth mention these values are available as "types" in thecmp
module:require('cmp').SelectBehavior
.
Some example config of these options are featured in nvim-cmp's readme.
If what you want is to extend the configuration of nvim-cmp, I suggest you change the preset to lsp-compe
. There is an example configuration in the Advance usage page.
cmp_action()
Is a function that returns methods meant to be used as mappings for nvim-cmp.
These are the supported methods:
tab_complete
: Enables completion when the cursor is inside a word. If the completion menu is visible it will navigate to the next item in the list. If the line is empty it uses the fallback.select_prev_or_fallback
: If the completion menu is visible navigate to the previous item in the list. Else, uses the fallback.toggle_completion
: If the completion menu is visible it cancels the process. Else, it triggers the completion menu.luasnip_jump_forward
: Go to the next placeholder in the snippet.luasnip_jump_backward
: Go to the previous placeholder in the snippet.luasnip_supertab
: If the completion menu is visible it will navigate to the next item in the list. If cursor is on top of the trigger of a snippet it'll expand it. If the cursor can jump to a snippet placeholder, it moves to it. If the cursor is in the middle of a word that doesn't trigger a snippet it displays the completion menu. Else, it uses the fallback.luasnip_shift_supertab
: If the completion menu is visible it will navigate to previous item in the list. If the cursor can navigate to a previous snippet placeholder, it moves to it. Else, it uses the fallback.
Quick note: "the fallback" is the default behavior of the key you assign to a method.
default_keymaps(opts)
Create LSP keybindings in the current buffer.
{opts}
supports the same properties as the setting set_lsp_keymaps and adds the following:
- buffer: (Number). Needs to be the "id" of an open buffer. The number
0
means the current buffer.
on_attach(callback)
Execute {callback}
function every time a server is attached to a buffer.
Let's say you want to disable all the default keybindings for lsp actions and diagnostics, and then declare your own.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = false,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.on_attach(function(client, bufnr)
local opts = {buffer = bufnr, remap = false}
vim.keymap.set('n', '<leader>r', '<cmd>lua vim.lsp.buf.rename()<cr>', opts)
-- more code ...
end)
lsp.setup()
ensure_installed(list)
Installs all the servers in {list}
if they are missing.
lsp.ensure_installed({
-- replace these with the language servers you want to install
'html',
'cssls',
'tsserver'
})
skip_server_setup(list)
Disables one or more language server. It tells lsp-zero to skip the initialization of the language servers provided. Its only effective when setup_servers_on_start is set to true
.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.skip_server_setup({'eslint', 'angularls'})
lsp.setup()
setup_servers(list)
Used to configure the servers specified in {list}
. If you provide the opts
property it will send those options to all language servers. Under the hood it calls .configure() for each server on {list}
.
local lsp_opts = {
single_file_support = false,
}
lsp.setup_servers({'html', 'cssls', opts = lsp_opts})
If the servers you want to call are installed globally use the option force
to skip any internal check.
lsp.setup_servers({'dartls', 'vls', force = true})
configure(name, opts)
Useful when you need to pass some custom options to a specific language server. Takes the same options as nvim-lspconfig
's setup function. You can find more details in the help page :help lspconfig-setup
.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.configure('tsserver', {
single_file_support = false,
on_attach = function(client, bufnr)
print('hello tsserver')
end
})
lsp.setup()
If you have a server installed globally you can use the option force_setup
to skip any internal check.
lsp.configure('dartls', {force_setup = true})
use(server, opts)
For when you want full control of the servers you want to use in particular project. It is meant to be called in project local config.
Ideally, you would setup some default values for your servers in your neovim config using .setup_servers() or .configure(). Example.
-- init.lua
local lsp = require('lsp-zero').preset({
name = 'per-project',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
})
lsp.configure('pyright', {
single_file_support = false
})
lsp.setup()
And then in your local config you can tweak the server options even more.
-- local config
local lsp = require('lsp-zero')
lsp.use('pyright', {
settings = {
python = {
analysis = {
extraPaths = {'/path/to/my/dependencies'},
}
}
}
})
Options from .configure() will be merged with the ones on .use()
and the server will be initialized.
.use()
can also take a list of servers. All the servers on the list will share the same options.
-- local config
local lsp = require('lsp-zero')
local lsp_opts = {
single_file_support = false
}
lsp.use({'html', 'cssls'}, lsp_opts)
set_server_config(opts)
Sets a default configuration for all LSP servers. You can find more details about {opts}
in the help page :help lspconfig-setup
.
lsp.set_server_config({
single_file_support = false,
})
build_options(server, opts)
Returns all the parameters necessary to start a language using nvim-lspconfig
's setup function. After calling this function you'll need to initialize the language server by other means.
The {opts}
table will be merged with the rest of the default options for {server}
.
This function was designed as an escape hatch, so you can call a language server using other tools.
For example, if you want to use rust-tools
, this is how you'll do it.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.skip_server_setup({'rust_analyzer'})
lsp.setup()
-- Initialize rust_analyzer with rust-tools
local rust_lsp = lsp.build_options('rust_analyzer', {})
require('rust-tools').setup({server = rust_lsp})
nvim_workspace(opts)
Configures the language server for lua with all the options needed to provide completions specific to neovim.
{opts}
supports two properties:
root_dir
: a function that determines the working directory of the language server.library
: a list of paths that the server should analyze.
By default only the runtime files of neovim and vim.fn.stdpath('config')
will be included. To add the path to every plugin you'll need to do this.
lsp.nvim_workspace({
library = vim.api.nvim_get_runtime_file('', true)
})
buffer_commands()
Create LSP commands in the current buffer.
format_on_save(opts)
Setup autoformat on save. This will to allow you to associate a language server with a list of filetypes.
Keep in mind it's only meant to allow one LSP server per filetype, this is so the formatting is consistent.
{opts}
supports the following properties:
servers: (Table) Key/value pair list. On the left hand side you must specify the name of a language server. On the right hand side you must provide a list of filetypes, this can be any pattern supported by the
FileType
autocommand.format_opts: (Table, optional). Configuration that will passed to the formatting function. It supports the following properties:
async: (Boolean, optional). If true it will send an asynchronous format request to the LSP server.
timeout_ms: (Number, optional). Time in milliseconds to block for formatting requests. Defaults to
10000
.formatting_options: (Table, optional). Can be used to set
FormattingOptions
, these options are sent to the language server. See FormattingOptions Specification.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.format_on_save({
format_opts = {
async = false,
timeout_ms = 10000
},
servers = {
['lua_ls'] = {'lua'},
['rust_analyzer'] = {'rust'},
}
})
lsp.setup()
buffer_autoformat(client, bufnr, opts)
Format the current buffer using the active language servers.
If {client}
argument is provided it will only use the LSP server associated with that client.
client: (Table, Optional) if provided it must be a lua table with a
name
property or an instance of vim.lsp.client.bufnr: (Number, Optional) if provided it must be the id of an open buffer.
opts: (Table, optional). Configuration that will passed to the formatting function. It supports the following properties:
timeout_ms: (Number, optional). Time in milliseconds to block for formatting requests. Has no effect when
async
is true. Defaults to10000
formatting_options: (Table, optional). Can be used to set
FormattingOptions
, these options are sent to the language server. See FormattingOptions Specification.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.on_attach(function(client, bufnr)
lsp.buffer_autoformat()
end)
lsp.setup()
async_autoformat(client, bufnr, opts)
Send a formatting request to {client}
. After the getting the response from the client it will save the file (again).
Here is how it works: when you save the file Neovim will write your changes without formatting. Then, lsp-zero will send a request to {client}
, when it gets the response it will apply the formatting and save the file again.
client: (Table) It must be an instance of vim.lsp.client.
bufnr: (Number, Optional) if provided it must be the id of an open buffer.
opts: (Table, Optional) Supports the following properties:
formatting_options: (Table, Optional) Settings send to the language server. These are the same settings as the
formatting_options
argument in vim.lsp.buf.format().timeout_ms: (Number, Optional) Defaults to 10000. Time in milliseconds to ignore the current format request.
Do not use this in the global on_attach
, call this function with the specific language server you want to format with.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.configure('tsserver', {
on_attach = function(client, bufnr)
lsp.async_autoformat(client, bufnr)
end
})
lsp.setup()
format_mapping(key, opts)
Configure {key}
to format the current buffer.
The idea here is that you associate a language server with a list of filetypes, so {key}
can format the buffer using only one LSP server.
{opts}
supports the following properties:
servers: (Table) Key/value pair list. On the left hand side you must specify the name of a language server. On the right hand side you must provide a list of filetypes, this can be any pattern supported by the
FileType
autocommand.mode: (Table, optional). The list of modes where the keybinding will be active. By default is set to
{'n', 'x'}
, which means normal mode and visual mode.format_opts: (Table, optional). Configuration that will passed to the formatting function. It supports the following properties:
async: If true the formatting request won't block. Defaults to false.
timeout_ms: (Number, optional). Time in milliseconds to block for formatting requests. Has no effect when
async
is true. Defaults to10000
.formatting_options: (Table, optional). Can be used to set
FormattingOptions
, these options are sent to the language server. See FormattingOptions Specification.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.format_mapping('gq', {
format_opts = {
async = false,
timeout_ms = 10000,
},
servers = {
['lua_ls'] = {'lua'},
['rust_analyzer'] = {'rust'},
}
})
lsp.setup()
new_server(opts)
lsp-zero will execute a user provided function to detect the root directory of the project when Neovim assigns the file type for a buffer. If the root directory is detected the LSP server will be attached to the file.
This function does not depend on lspconfig
, it's a wrapper around a Neovim function called vim.lsp.start_client().
{opts}
supports every property vim.lsp.start_client
supports with a few changes:
filestypes
: Can be list filetype names. This can be any pattern theFileType
autocommand accepts.root_dir
: Can be a function, it'll be executed after Neovim assigns the file type for a buffer. If it returns a string that will be considered the root directory for the project.
Other important properties are:
cmd
: (Table) A lua table with the arguments necessary to start the language server.name
: (String) This is the name Neovim will assign to the client object.on_attach
: (Function) A function that will be executed after the language server gets attached to a buffer.
Here is an example that starts the typescript language server on javascript and typescript, but only in a project that package.json in the current directory or any of its parent folders.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.new_server({
name = 'tsserver',
cmd = {'typescript-language-server', '--stdio'},
filetypes = {'javascript', 'typescript'},
root_dir = function()
return lsp.dir.find_first({'package.json'})
end
})
lsp.setup()
set_sign_icons(opts)
Defines the sign icons that appear in the gutter. If {opts}
is not provided the default icons will be used.
{opts}
table supports these properties:
error
: Text for the error signs.warn
: Text for the warning signs.hint
: Text for the hint signs.info
: Text for the information signs.
highlight_symbol(client, bufnr)
Uses the CursorHold
event to trigger a document highlight request. In other words, it will highlight the symbol under the cursor.
For this to work properly your colorscheme needs to set these highlight groups: LspReferenceRead
, LspReferenceText
and LspReferenceWrite
.
Keep in mind the event CursorHold
depends on the updatetime
option. If you want the highlight to happen fast, you will need to set this option to a "low" value.
vim.opt.updatetime = 400
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.on_attach(function(client, bufnr)
lsp.highlight_symbol(client, bufnr)
end)
lsp.setup()
dir.find_first(list)
Checks the parent directories and returns the path to the first folder that has a file in {list}
. This is useful to detect the root directory.
Note: search will stop once it gets to your "HOME" folder.
{list}
supports the following properties:
path: (String) The path from where it should start looking for the files in
{list}
.buffer: (Boolean) When set to
true
use the path of the current buffer.stop: (String) Defaults to the HOME directory. Stop the search on this directory.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.configure('tsserver' {
root_dir = function()
--- project root will be the first directory that has
--- either package.json or node_modules.
return lsp.dir.find_first({'package.json', 'node_modules'})
end
})
lsp.setup()
dir.find_all(list)
Checks the parent directories and returns the path to the first folder that has all the files in {list}
.
Note: by default the search will stop once it gets to your "HOME" folder.
{list}
supports the following properties:
path: (String) The path from where it should start looking for the files in
{list}
.buffer: (Boolean) When set to
true
use the path of the current buffer.stop: (String) Defaults to the HOME directory. Stop the search on this directory.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
lsp.configure('vuels' {
root_dir = function()
--- project root will be the directory that has
--- package.json + vetur config
return lsp.dir.find_all({'package.json', 'vetur.config.js'})
end
})
lsp.setup()
defaults.diagnostics(opts)
Returns the configuration for diagnostics. If you provide the {opts}
table it'll merge it with the defaults, this way you can extend or change the values easily.
defaults.cmp_sources()
Returns the list of "sources" used in nvim-cmp
.
defaults.cmp_mappings(opts)
Returns a table with the default keybindings for nvim-cmp
. If you provide the {opts}
table it'll merge it with the defaults, this way you can extend or change the values easily.
Here is an example that disables completion with tab and replace it with Ctrl + space
.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = true,
suggest_lsp_servers = false,
})
local cmp = require('cmp')
lsp.setup_nvim_cmp({
mapping = lsp.defaults.cmp_mappings({
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.abort(),
-- disable completion with tab
['<Tab>'] = vim.NIL,
['<S-Tab>'] = vim.NIL,
-- disable confirm with Enter key
['<CR>'] = vim.NIL,
})
})
lsp.setup()
defaults.cmp_config(opts)
Returns the entire configuration table for nvim-cmp. If you provide the {opts}
table it'll merge it with the defaults, this way you can extend or change the values easily.
In this example we set manage_nvim_cmp
to false
then seutp nvim-cmp directly.
local lsp = require('lsp-zero').preset({
name = 'minimal',
set_lsp_keymaps = true,
manage_nvim_cmp = false,
suggest_lsp_servers = false,
})
lsp.setup()
vim.opt.completeopt = {'menu', 'menuone', 'noselect'}
local cmp = require('cmp')
local cmp_config = lsp.defaults.cmp_config({
window = {
completion = cmp.config.window.bordered()
}
})
cmp.setup(cmp_config)
defaults.nvim_workspace()
Returns the neovim specific settings for lua_ls
language server.
extend_lspconfig(opts)
The purpose of this function is to allow you to interact with lspconfig
directly and still enjoy all the keybindings and commands lsp-zero offers.
It "extends" the default configuration in lspconfig
, adding two options to it: capabilities
and on_attach
.
Note: don't use it along side .setup(). Its meant to be independent of any settings provided by presets.
This is the intended usage:
require('mason').setup()
require('mason-lspconfig').setup()
require('lsp-zero').extend_lspconfig()
require('lspconfig').tsserver.setup({})
Notice here it can coexists with other plugins. Allowing you to have full control of your configuration.
{opts}
table supports the following properties:
set_lsp_keymaps
: When set totrue
(the default) it creates keybindings linked to lsp actions. You can also provide a list of keys you want to omit, lsp-zero will not bind it to anything (see example below). When set tofalse
all keybindings are disabled.capabilities
: These are the "client capabilities" a language server expects. This argument will be merge nvim-cmp's default capabilities if you have it installed.on_attach
: This must be a function. Think of it as "global"on_attach
so you don't have to keep passing a function to each server's setup function.
Here's an example that showcase each option.
-- There is no need to copy any of this
require('lsp-zero').extend_lspconfig({
set_lsp_keymaps = {omit = {'<C-k>', 'gl'}},
on_attach = function(client, bufnr)
print('hello there')
end,
capabilities = {
textDocument = {
foldingRange = {
dynamicRegistration = false,
lineFoldingOnly = true
}
}
}
})