aboutsummaryrefslogtreecommitdiff
path: root/runtime/doc/lsp.txt
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/doc/lsp.txt')
-rw-r--r--runtime/doc/lsp.txt295
1 files changed, 107 insertions, 188 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 26850b3683..c4c164ab6c 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -1,18 +1,18 @@
-*lsp.txt* The Language Server Protocol
+*lsp.txt* Nvim LSP API
- NVIM REFERENCE MANUAL
+ NVIM REFERENCE MANUAL
-Neovim Language Server Protocol (LSP) API
+Nvim Language Server Protocol (LSP) API *lsp*
-Neovim exposes a powerful API that conforms to Microsoft's published Language
-Server Protocol specification. The documentation can be found here:
+Nvim is a client to the Language Server Protocol:
https://microsoft.github.io/language-server-protocol/
+ Type |gO| to see the table of contents.
================================================================================
- *lsp-api*
+LSP API *lsp-api*
Neovim exposes a API for the language server protocol. To get the real benefits
of this API, a language server must be installed.
@@ -24,106 +24,15 @@ After installing a language server to your machine, you must let Neovim know
how to start and interact with that language server.
To do so, you can either:
-- Use the |vim.lsp.add_filetype_config()|, which solves the common use-case of
- a single server for one or more filetypes. This can also be used from vim
- via |lsp#add_filetype_config()|.
+- Use https://github.com/neovim/nvim-lsp and one of the existing servers there
+ or set up a new one using the `nvim_lsp/skeleton` interface (and contribute
+ it if you find it useful). This uses |vim.lsp.start_client()| under the
+ hood.
- Or |vim.lsp.start_client()| and |vim.lsp.buf_attach_client()|. These are the
backbone of the LSP API. These are easy to use enough for basic or more
complex configurations such as in |lsp-advanced-js-example|.
================================================================================
- *lsp-filetype-config*
-
-These are utilities specific to filetype based configurations.
-
- *lsp#add_filetype_config()*
- *vim.lsp.add_filetype_config()*
-lsp#add_filetype_config({config}) for Vim.
-vim.lsp.add_filetype_config({config}) for Lua
-
- These are functions which can be used to create a simple configuration which
- will start a language server for a list of filetypes based on the |FileType|
- event.
- It will lazily start start the server, meaning that it will only start once
- a matching filetype is encountered.
-
- The {config} options are the same as |vim.lsp.start_client()|, but
- with a few additions and distinctions:
-
- Additional parameters:~
- `filetype`
- {string} or {list} of filetypes to attach to.
- `name`
- A unique identifying string among all other servers configured with
- |vim.lsp.add_filetype_config|.
-
- Differences:~
- `root_dir`
- Will default to |getcwd()| instead of being required.
-
- NOTE: the function options in {config} like {config.on_init} are for Lua
- callbacks, not Vim callbacks.
->
- " Go example
- call lsp#add_filetype_config({
- \ 'filetype': 'go',
- \ 'name': 'gopls',
- \ 'cmd': 'gopls'
- \ })
- " Python example
- call lsp#add_filetype_config({
- \ 'filetype': 'python',
- \ 'name': 'pyls',
- \ 'cmd': 'pyls'
- \ })
- " Rust example
- call lsp#add_filetype_config({
- \ 'filetype': 'rust',
- \ 'name': 'rls',
- \ 'cmd': 'rls',
- \ 'capabilities': {
- \ 'clippy_preference': 'on',
- \ 'all_targets': v:false,
- \ 'build_on_save': v:true,
- \ 'wait_to_build': 0
- \ }})
-<
->
- -- From Lua
- vim.lsp.add_filetype_config {
- name = "clangd";
- filetype = {"c", "cpp"};
- cmd = "clangd -background-index";
- capabilities = {
- offsetEncoding = {"utf-8", "utf-16"};
- };
- on_init = vim.schedule_wrap(function(client, result)
- if result.offsetEncoding then
- client.offset_encoding = result.offsetEncoding
- end
- end)
- }
-<
- *vim.lsp.copy_filetype_config()*
-vim.lsp.copy_filetype_config({existing_name}, [{override_config}])
-
- You can use this to copy an existing filetype configuration and change it by
- specifying {override_config} which will override any properties in the
- existing configuration. If you don't specify a new unique name with
- {override_config.name} then it will try to create one and return it.
-
- Returns:~
- `name` the new configuration name.
-
- *vim.lsp.get_filetype_client_by_name()*
-vim.lsp.get_filetype_client_by_name({name})
-
- Use this to look up a client by its name created from
- |vim.lsp.add_filetype_config()|.
-
- Returns nil if the client is not active or the name is not valid.
-
-================================================================================
*lsp-core-api*
These are the core api functions for working with clients. You will mainly be
using |vim.lsp.start_client()| and |vim.lsp.buf_attach_client()| for operations
@@ -178,8 +87,8 @@ vim.lsp.start_client({config})
`callbacks`
A {table} of whose keys are language server method names and the values
are `function(err, method, params, client_id)` See |lsp-callbacks| for
- more. This will be combined with |lsp-builtin-callbacks| to provide
- defaults.
+ more. This will be combined with |lsp-default-callbacks| to resolve
+ the callbacks for a client as a fallback.
`init_options`
A {table} of values to pass in the initialization request as
@@ -203,6 +112,12 @@ vim.lsp.start_client({config})
`vim.lsp.client_errors[code]` can be used to retrieve a human
understandable string.
+ `before_init(initialize_params, config)`
+ A function which is called *before* the request `initialize` is completed.
+ `initialize_params` contains the parameters we are sending to the server
+ and `config` is the config that was passed to `start_client()` for
+ convenience. You can use this to modify parameters before they are sent.
+
`on_init(client, initialize_result)`
A function which is called after the request `initialize` is completed.
`initialize_result` contains `capabilities` and anything else the server
@@ -346,75 +261,81 @@ vim.lsp.rpc_response_error({code}, [{message}], [{data}])
the server.
================================================================================
- *vim.lsp.builtin_callbacks*
-
-The |vim.lsp.builtin_callbacks| table contains the default |lsp-callbacks|
-that are used when creating a new client. The keys are the LSP method names.
-
-The following requests and notifications have built-in callbacks defined to
-handle the response in an idiomatic way.
-
- textDocument/completion
- textDocument/declaration
- textDocument/definition
- textDocument/hover
- textDocument/implementation
- textDocument/rename
- textDocument/signatureHelp
- textDocument/typeDefinition
+LSP CALLBACKS *lsp-callbacks*
+
+DEFAULT CALLBACKS ~
+ *vim.lsp.default_callbacks*
+The `vim.lsp.default_callbacks` table defines default callbacks used when
+creating a new client. Keys are LSP method names: >
+
+ :lua print(vim.inspect(vim.tbl_keys(vim.lsp.default_callbacks)))
+
+These LSP requests/notifications are defined by default:
+
+ textDocument/publishDiagnostics
window/logMessage
window/showMessage
-You can check these via `vim.tbl_keys(vim.lsp.builtin_callbacks)`.
+You can check these via `vim.tbl_keys(vim.lsp.default_callbacks)`.
-These will be automatically used and can be overridden by users (either by
-modifying the |vim.lsp.builtin_callbacks| object or on a per-client basis
-by passing in a table via the {callbacks} parameter on |vim.lsp.start_client|
-or |vim.lsp.add_filetype_config|.
+These will be used preferrentially in `vim.lsp.buf` methods when handling
+requests. They will also be used when responding to server requests and
+notifications.
-More information about callbacks can be found in |lsp-callbacks|.
+Use cases:
+- Users can modify this to customize to their preferences.
+- UI plugins can modify this by assigning to
+ `vim.lsp.default_callbacks[method]` so as to provide more specialized
+ handling, allowing you to leverage the UI capabilities available. UIs should
+ try to be conscientious of any existing changes the user may have set
+ already by checking for existing values.
-================================================================================
- *lsp-callbacks*
+Any callbacks passed directly to `request` methods on a server client will
+have the highest precedence, followed by the `default_callbacks`.
+
+You can override the default handlers,
+- globally: by modifying the `vim.lsp.default_callbacks` table
+- per-client: by passing the {callbacks} table parameter to
+ |vim.lsp.start_client|
+
+Each handler has this signature: >
+
+ function(err, method, params, client_id)
Callbacks are functions which are called in a variety of situations by the
client. Their signature is `function(err, method, params, client_id)` They can
-be set by the {callbacks} parameter for |vim.lsp.start_client| and
-|vim.lsp.add_filetype_config| or via the |vim.lsp.builtin_callbacks|.
-
-This will be called for:
-- notifications from the server, where `err` will always be `nil`
-- requests initiated by the server. The parameter `err` will be `nil` here as
- well.
- For these, you can respond by returning two values: `result, err` The
- err must be in the format of an RPC error, which is
- `{ code, message, data? }`
- You can use |vim.lsp.rpc_response_error()| to help with creating this object.
-- as a callback for requests initiated by the client if the request doesn't
- explicitly specify a callback (such as in |vim.lsp.buf_request|).
+be set by the {callbacks} parameter for |vim.lsp.start_client| or via the
+|vim.lsp.default_callbacks|.
+
+Handlers are called for:
+- Notifications from the server (`err` is always `nil`).
+- Requests initiated by the server (`err` is always `nil`).
+ The handler can respond by returning two values: `result, err`
+ where `err` must be shaped like an RPC error:
+ `{ code, message, data? }`
+ You can use |vim.lsp.rpc_response_error()| to create this object.
+- Handling requests initiated by the client if the request doesn't explicitly
+ specify a callback (such as in |vim.lsp.buf_request|).
================================================================================
- *vim.lsp.protocol*
-vim.lsp.protocol
+VIM.LSP.PROTOCOL *vim.lsp.protocol*
- Contains constants as described in the Language Server Protocol
- specification and helper functions for creating protocol related objects.
+The `vim.lsp.protocol` module provides constants defined in the LSP
+specification, and helper functions for creating protocol-related objects.
https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
- Useful examples are `vim.lsp.protocol.ErrorCodes`. These objects allow
- reverse lookup by either the number or string name.
+Useful examples are `vim.lsp.protocol.ErrorCodes`. These objects allow reverse
+lookup by either the number or string name.
e.g. vim.lsp.protocol.TextDocumentSyncKind.Full == 1
vim.lsp.protocol.TextDocumentSyncKind[1] == "Full"
Utility functions used internally are:
- `vim.lsp.make_client_capabilities()`
+ `vim.lsp.protocol.make_client_capabilities()`
Make a ClientCapabilities object. These are the builtin
capabilities.
- `vim.lsp.make_text_document_position_params()`
- Make a TextDocumentPositionParams object.
- `vim.lsp.resolve_capabilities(server_capabilites)`
+ `vim.lsp.protocol.resolve_capabilities(server_capabilites)`
Creates a normalized object describing capabilities from the server
capabilities.
@@ -482,18 +403,16 @@ vim.lsp.buf_notify({bufnr}, {method}, {params})
================================================================================
*lsp-logging*
- *lsp#set_log_level()*
-lsp#set_log_level({level})
+ *vim.lsp.set_log_level()*
+vim.lsp.set_log_level({level})
You can set the log level for language server client logging.
Possible values: "trace", "debug", "info", "warn", "error"
Default: "warn"
- Example: `call lsp#set_log_level("debug")`
+ Example: `lua vim.lsp.set_log_level("debug")`
- *lsp#get_log_path()*
*vim.lsp.get_log_path()*
-lsp#get_log_path()
vim.lsp.get_log_path()
Returns the path that LSP logs are written.
@@ -508,46 +427,46 @@ vim.lsp.log_levels
================================================================================
*lsp-omnifunc*
*vim.lsp.omnifunc()*
- *lsp#omnifunc*
-lsp#omnifunc({findstart}, {base})
vim.lsp.omnifunc({findstart}, {base})
To configure omnifunc, add the following in your init.vim:
>
- set omnifunc=lsp#omnifunc
+ " Configure for python
+ autocmd Filetype python setl omnifunc=v:lua.vim.lsp.omnifunc
+
+ " Or with on_attach
+ start_client {
+ ...
+ on_attach = function(client, bufnr)
+ vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
+ end;
+ }
- " This is optional, but you may find it useful
- autocmd CompleteDone * pclose
+ " This is optional, but you may find it useful
+ autocmd CompleteDone * pclose
<
================================================================================
- *lsp-vim-functions*
+LSP FUNCTIONS *lsp-vim-functions*
+
+To use the functions from vim, it is recommended to use |v:lua| to interface
+with the Lua functions. No direct vim functions are provided, but the
+interface is still easy to use from mappings.
These methods can be used in mappings and are the equivalent of using the
request from lua as follows:
>
- lua vim.lsp.buf_request(0, "textDocument/hover", vim.lsp.protocol.make_text_document_position_params())
-<
-
- lsp#text_document_declaration()
- lsp#text_document_definition()
- lsp#text_document_hover()
- lsp#text_document_implementation()
- lsp#text_document_signature_help()
- lsp#text_document_type_definition()
-
->
" Example config
- autocmd Filetype rust,python,go,c,cpp setl omnifunc=lsp#omnifunc
- nnoremap <silent> ;dc :call lsp#text_document_declaration()<CR>
- nnoremap <silent> ;df :call lsp#text_document_definition()<CR>
- nnoremap <silent> ;h :call lsp#text_document_hover()<CR>
- nnoremap <silent> ;i :call lsp#text_document_implementation()<CR>
- nnoremap <silent> ;s :call lsp#text_document_signature_help()<CR>
- nnoremap <silent> ;td :call lsp#text_document_type_definition()<CR>
+ autocmd Filetype rust,python,go,c,cpp setl omnifunc=v:lua.vim.lsp.omnifunc
+ nnoremap <silent> ;dc <cmd>lua vim.lsp.buf.declaration()<CR>
+ nnoremap <silent> ;df <cmd>lua vim.lsp.buf.definition()<CR>
+ nnoremap <silent> ;h <cmd>lua vim.lsp.buf.hover()<CR>
+ nnoremap <silent> ;i <cmd>lua vim.lsp.buf.implementation()<CR>
+ nnoremap <silent> ;s <cmd>lua vim.lsp.buf.signature_help()<CR>
+ nnoremap <silent> ;td <cmd>lua vim.lsp.buf.type_definition()<CR>
<
================================================================================
- *lsp-advanced-js-example*
+LSP EXAMPLE *lsp-advanced-js-example*
For more advanced configurations where just filtering by filetype isn't
sufficient, you can use the `vim.lsp.start_client()` and
@@ -569,7 +488,7 @@ The example will:
local stat = vim.loop.fs_stat(filename)
return stat and stat.type == 'directory' or false
end
-
+
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
-- Asumes filepath is a file.
local function dirname(filepath)
@@ -580,11 +499,11 @@ The example will:
end)
return result, is_changed
end
-
+
local function path_join(...)
return table.concat(vim.tbl_flatten {...}, path_sep)
end
-
+
-- Ascend the buffer's path until we find the rootdir.
-- is_root_path is a function which returns bool
local function buffer_find_root_dir(bufnr, is_root_path)
@@ -606,7 +525,7 @@ The example will:
end
end
end
-
+
-- A table to store our root_dir to client_id lookup. We want one LSP per
-- root directory, and this is how we assert that.
local javascript_lsps = {}
@@ -617,14 +536,14 @@ The example will:
["typescript"] = true;
["typescript.jsx"] = true;
}
-
+
-- Create a template configuration for a server to start, minus the root_dir
-- which we will specify later.
local javascript_lsp_config = {
name = "javascript";
cmd = { path_join(os.getenv("JAVASCRIPT_LANGUAGE_SERVER_DIRECTORY"), "lib", "language-server-stdio.js") };
}
-
+
-- This needs to be global so that we can call it from the autocmd.
function check_start_javascript_lsp()
local bufnr = vim.api.nvim_get_current_buf()
@@ -641,7 +560,7 @@ The example will:
end)
-- We couldn't find a root directory, so ignore this file.
if not root_dir then return end
-
+
-- Check if we have a client alredy or start and store it.
local client_id = javascript_lsps[root_dir]
if not client_id then
@@ -655,7 +574,7 @@ The example will:
-- are already attached.
vim.lsp.buf_attach_client(bufnr, client_id)
end
-
+
vim.api.nvim_command [[autocmd BufReadPost * lua check_start_javascript_lsp()]]
<