aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrice Peterson <patrice.peterson@mailbox.org>2020-08-19 18:17:08 +0200
committerPatrice Peterson <patrice.peterson@mailbox.org>2020-08-23 13:48:25 +0200
commitac05343a1023874243ee9fdd490c21c42a737157 (patch)
tree2466eb3c28b09b8e77ba7e1d3696555672fbb38e
parent8c49e3d50959e24dadd688f56a18f104bd5fd934 (diff)
downloadrneovim-ac05343a1023874243ee9fdd490c21c42a737157.tar.gz
rneovim-ac05343a1023874243ee9fdd490c21c42a737157.tar.bz2
rneovim-ac05343a1023874243ee9fdd490c21c42a737157.zip
Add docs for most vim.lsp methods
Most of the lsp.log will be addressed in a separate PR.
-rw-r--r--runtime/doc/api.txt11
-rw-r--r--runtime/doc/lsp.txt814
-rw-r--r--runtime/lua/vim/lsp.lua255
-rw-r--r--runtime/lua/vim/lsp/buf.lua98
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua47
-rw-r--r--runtime/lua/vim/lsp/log.lua11
-rw-r--r--runtime/lua/vim/lsp/protocol.lua11
-rw-r--r--runtime/lua/vim/lsp/rpc.lua132
-rw-r--r--runtime/lua/vim/lsp/util.lua308
-rwxr-xr-xscripts/gen_vimdoc.py6
-rw-r--r--src/nvim/api/vim.c8
11 files changed, 1237 insertions, 464 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index ea3a8242ae..7ac7f7d7ea 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -734,13 +734,14 @@ nvim_feedkeys({keys}, {mode}, {escape_csi}) *nvim_feedkeys()*
On execution error: does not fail, but updates v:errmsg.
- If you need to input sequences like <C-o> use nvim_replace_termcodes
- to replace the termcodes and then pass the resulting string to
- nvim_feedkeys. You'll also want to enable escape_csi.
+ If you need to input sequences like <C-o> use
+ |nvim_replace_termcodes| to replace the termcodes and then
+ pass the resulting string to nvim_feedkeys. You'll also want
+ to enable escape_csi.
Example: >
- :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
- :call nvim_feedkeys(key, 'n', v:true)
+ :let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
+ :call nvim_feedkeys(key, 'n', v:true)
<
Parameters: ~
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index b934d2dfa0..9db478ac41 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -353,9 +353,6 @@ buf_get_clients({bufnr}) *vim.lsp.buf_get_clients()*
{bufnr} (optional, number): Buffer handle, or 0 for
current
-buf_get_full_text({bufnr}) *vim.lsp.buf_get_full_text()*
- TODO: Documentation
-
buf_is_attached({bufnr}, {client_id}) *vim.lsp.buf_is_attached()*
Checks if a buffer is attached for a particular client.
@@ -416,71 +413,69 @@ buf_request_sync({bufnr}, {method}, {params}, {timeout_ms})
error, returns `(nil, err)` where `err` is a string
describing the failure reason.
-cancel_request({id}) *vim.lsp.cancel_request()*
- TODO: Documentation
-
client() *vim.lsp.client*
- LSP client object.
+ LSP client object. You can get an active client object via
+ |vim.lsp.get_client_by_id()| or
+ |vim.lsp.get_active_clients()|.
• Methods:
- • request(method, params, [callback]) Send a request to the
- server. If callback is not specified, it will use
+ • request(method, params, [callback], bufnr) Send a request
+ to the server. This is a thin wrapper around
+ {client.rpc.request} with some additional checking. If
+ {callback} is not specified, it will use
{client.callbacks} to try to find a callback. If one is
- not found there, then an error will occur. This is a thin
- wrapper around {client.rpc.request} with some additional
- checking. Returns a boolean to indicate if the
- notification was successful. If it is false, then it will
- always be false (the client has shutdown). If it was
- successful, then it will return the request id as the
- second result. You can use this with `notify("$/cancel", {
- id = request_id })` to cancel the request. This helper is
- made automatically with |vim.lsp.buf_request()| Returns:
- status, [client_id]
- • notify(method, params) This is just {client.rpc.notify}()
- Returns a boolean to indicate if the notification was
- successful. If it is false, then it will always be false
- (the client has shutdown). Returns: status
- • cancel_request(id) This is just
- {client.rpc.notify}("$/cancelRequest", { id = id })
- Returns the same as `notify()` .
+ not found there, then an error will occur. Returns:
+ {status}, {[client_id]}. {status} is a boolean indicating
+ if the notification was successful. If it is `false` ,
+ then it will always be `false` (the client has shutdown).
+ If {status} is `true` , the function returns {request_id}
+ as the second result. You can use this with
+ `client.cancel_request(request_id)` to cancel the request.
+ • notify(method, params) Send a notification to an LSP
+ server. Returns: a boolean to indicate if the notification
+ was successful. If it is false, then it will always be
+ false (the client has shutdown).
+ • cancel_request(id) Cancels a request with a given request
+ id. Returns: same as `notify()` .
• stop([force]) Stop a client, optionally with force. By
default, it will just ask the server to shutdown without
force. If you request to stop a client which has
previously been requested to shutdown, it will
automatically escalate and force shutdown.
- • is_stopped() Returns true if the client is fully stopped.
+ • is_stopped() Checks whether a client is stopped. Returns:
+ true if the client is fully stopped.
+ • on_attach(bufnr) Runs the on_attach function from the
+ client's config if it was defined.
• Members
- • id (number): The id allocated to the client.
- • name (string): If a name is specified on creation, that
+ • {id} (number): The id allocated to the client.
+ • {name} (string): If a name is specified on creation, that
will be used. Otherwise it is just the client id. This is
used for logs and messages.
- • offset_encoding (string): The encoding used for
+ • {rpc} (table): RPC client object, for low level
+ interaction with the client. See |vim.lsp.rpc.start()|.
+ • {offset_encoding} (string): The encoding used for
communicating with the server. You can modify this in the
- `on_init` method before text is sent to the server.
- • callbacks (table): The callbacks used by the client as
+ `config` 's `on_init` method before text is sent to the
+ server.
+ • {callbacks} (table): The callbacks used by the client as
described in |lsp-callbacks|.
- • config (table): copy of the table that was passed by the
+ • {config} (table): copy of the table that was passed by the
user to |vim.lsp.start_client()|.
- • server_capabilities (table): Response from the server sent
- on `initialize` describing the server's capabilities.
- • resolved_capabilities (table): Normalized table of
+ • {server_capabilities} (table): Response from the server
+ sent on `initialize` describing the server's capabilities.
+ • {resolved_capabilities} (table): Normalized table of
capabilities that we have detected based on the initialize
response from the server in `server_capabilities` .
client_is_stopped({client_id}) *vim.lsp.client_is_stopped()*
- TODO: Documentation
+ Checks whether a client is stopped.
- *vim.lsp.define_default_sign()*
-define_default_sign({name}, {properties})
- TODO: Documentation
-
-err_message({...}) *vim.lsp.err_message()*
- TODO: Documentation
+ Parameters: ~
+ {client_id} (Number)
- *vim.lsp.for_each_buffer_client()*
-for_each_buffer_client({bufnr}, {callback})
- TODO: Documentation
+ Return: ~
+ true if client is stopped, false otherwise.
get_active_clients() *vim.lsp.get_active_clients()*
Gets all active clients.
@@ -499,25 +494,10 @@ get_client_by_id({client_id}) *vim.lsp.get_client_by_id()*
|vim.lsp.client| object, or nil
get_log_path() *vim.lsp.get_log_path()*
- TODO: Documentation
-
-initialize() *vim.lsp.initialize()*
- TODO: Documentation
-
-is_dir({filename}) *vim.lsp.is_dir()*
- TODO: Documentation
-
-is_stopped() *vim.lsp.is_stopped()*
- TODO: Documentation
+ Gets the path of the logfile used by the LSP client.
-next_client_id() *vim.lsp.next_client_id()*
- TODO: Documentation
-
-notification({method}, {params}) *vim.lsp.notification()*
- TODO: Documentation
-
-notify({...}) *vim.lsp.notify()*
- TODO: Documentation
+ Return: ~
+ (String) Path to logfile.
omnifunc({findstart}, {base}) *vim.lsp.omnifunc()*
Implements 'omnifunc' compatible LSP completion.
@@ -538,30 +518,6 @@ omnifunc({findstart}, {base}) *vim.lsp.omnifunc()*
|complete-items|
|CompleteDone|
-on_error({code}, {err}) *vim.lsp.on_error()*
- TODO: Documentation
-
-on_exit({code}, {signal}) *vim.lsp.on_exit()*
- TODO: Documentation
-
-once({fn}) *vim.lsp.once()*
- TODO: Documentation
-
-optional_validator({fn}) *vim.lsp.optional_validator()*
- TODO: Documentation
-
-request({method}, {params}, {callback}, {bufnr}) *vim.lsp.request()*
- TODO: Documentation
-
-resolve_bufnr({bufnr}) *vim.lsp.resolve_bufnr()*
- TODO: Documentation
-
-resolve_callback({method}) *vim.lsp.resolve_callback()*
- TODO: Documentation
-
-server_request({method}, {params}) *vim.lsp.server_request()*
- TODO: Documentation
-
set_log_level({level}) *vim.lsp.set_log_level()*
Sets the global log level for LSP logging.
@@ -582,6 +538,9 @@ start_client({config}) *vim.lsp.start_client()*
Parameters `cmd` and `root_dir` are required.
+ The following parameters describe fields in the {config}
+ table.
+
Parameters: ~
{root_dir} (required, string) Directory where the
LSP server will base its rootUri on
@@ -612,13 +571,13 @@ start_client({config}) *vim.lsp.start_client()*
array.
{callbacks} Map of language server method names to `function(err, method, params,
client_id)` handler. Invoked for:
- • Notifications from the server, where
+ • Notifications to the server, where
`err` will always be `nil` .
- • Requests initiated by the server. For
- these you can respond by returning
- two values: `result, err` where err
- must be shaped like a RPC error, i.e.
- `{ code, message, data? }` . Use
+ • Requests by the server. For these you
+ can respond by returning two values:
+ `result, err` where err must be
+ shaped like a RPC error, i.e. `{
+ code, message, data? }` . Use
|vim.lsp.rpc_response_error()| to
help with this.
• Default callback for client requests
@@ -647,8 +606,9 @@ start_client({config}) *vim.lsp.start_client()*
where `params` contains the parameters
being sent to the server and `config`
is the config that was passed to
- `start_client()` . You can use this to
- modify parameters before they are sent.
+ |vim.lsp.start_client()|. You can use
+ this to modify parameters before they
+ are sent.
{on_init} Callback (client, initialize_result)
invoked after LSP "initialize", where
`result` is a table of `capabilities`
@@ -680,9 +640,6 @@ start_client({config}) *vim.lsp.start_client()*
error). Use `on_init` to do any actions once the client
has been initialized.
-stop({force}) *vim.lsp.stop()*
- TODO: Documentation
-
stop_client({client_id}, {force}) *vim.lsp.stop_client()*
Stops a client(s).
@@ -702,26 +659,10 @@ stop_client({client_id}, {force}) *vim.lsp.stop_client()*
thereof
{force} boolean (optional) shutdown forcefully
- *vim.lsp.text_document_did_open_handler()*
-text_document_did_open_handler({bufnr}, {client})
- TODO: Documentation
-
-unsupported_method({method}) *vim.lsp.unsupported_method()*
- TODO: Documentation
-
-validate_client_config({config}) *vim.lsp.validate_client_config()*
- TODO: Documentation
-
-validate_encoding({encoding}) *vim.lsp.validate_encoding()*
- TODO: Documentation
-
==============================================================================
Lua module: vim.lsp.protocol *lsp-protocol*
-ifnil({a}, {b}) *vim.lsp.protocol.ifnil()*
- TODO: Documentation
-
*vim.lsp.protocol.make_client_capabilities()*
make_client_capabilities()
Gets a new ClientCapabilities object describing the LSP client
@@ -739,28 +680,38 @@ resolve_capabilities({server_capabilities})
characters to match in a path segment (e.g., `example.[!0-9]`
to match on `example.a` , `example.b` , but not `example.0` )
- *vim.lsp.protocol.transform_schema_comments()*
-transform_schema_comments()
- TODO: Documentation
-
- *vim.lsp.protocol.transform_schema_to_table()*
-transform_schema_to_table()
- TODO: Documentation
-
==============================================================================
Lua module: vim.lsp.buf *lsp-buf*
clear_references() *vim.lsp.buf.clear_references()*
- TODO: Documentation
+ Removes document highlights from current buffer.
code_action({context}) *vim.lsp.buf.code_action()*
- TODO: Documentation
+ Select a code action from the input list that is available at
+ the current cursor position.
+
+ Parameters: ~
+ {context} (table, optional) Valid `CodeActionContext`
+ object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
completion({context}) *vim.lsp.buf.completion()*
Retrieves the completion items at the current cursor position.
Can only be called in Insert mode.
+ Parameters: ~
+ {context} (context support not yet implemented)
+ Additional information about the context in
+ which a completion was triggered (how it was
+ triggered, and by which trigger character, if
+ applicable)
+
+ See also: ~
+ |vim.lsp.protocol.constants.CompletionTriggerKind|
+
declaration() *vim.lsp.buf.declaration()*
Jumps to the declaration of the symbol under the cursor.
@@ -782,14 +733,25 @@ document_symbol() *vim.lsp.buf.document_symbol()*
window.
execute_command({command}) *vim.lsp.buf.execute_command()*
- TODO: Documentation
+ Execute an LSP server command.
+
+ Parameters: ~
+ {command} A valid `ExecuteCommandParams` object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
formatting({options}) *vim.lsp.buf.formatting()*
Formats the current buffer.
- The optional {options} table can be used to specify
- FormattingOptions, a list of which is available at https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting . Some unspecified options will be automatically derived from
- the current Neovim options.
+ Parameters: ~
+ {options} (optional, table) Can be used to specify
+ FormattingOptions. Some unspecified options
+ will be automatically derived from the current
+ Neovim options.
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
*vim.lsp.buf.formatting_sync()*
formatting_sync({options}, {timeout_ms})
@@ -797,7 +759,15 @@ formatting_sync({options}, {timeout_ms})
Useful for running on save, to make sure buffer is formatted
prior to being saved. {timeout_ms} is passed on to
- |vim.lsp.buf_request_sync()|.
+ |vim.lsp.buf_request_sync()|. Example:
+>
+
+ vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]]
+<
+
+ Parameters: ~
+ {options} Table with valid `FormattingOptions` entries
+ {timeout_ms} (number) Request timeout
hover() *vim.lsp.buf.hover()*
Displays hover information about the symbol under the cursor
@@ -808,29 +778,49 @@ implementation() *vim.lsp.buf.implementation()*
Lists all the implementations for the symbol under the cursor
in the quickfix window.
-npcall({fn}, {...}) *vim.lsp.buf.npcall()*
- TODO: Documentation
+incoming_calls() *vim.lsp.buf.incoming_calls()*
+ Lists all the call sites of the symbol under the cursor in the
+ |quickfix| window. If the symbol can resolve to multiple
+ items, the user can pick one in the |inputlist|.
-ok_or_nil({status}, {...}) *vim.lsp.buf.ok_or_nil()*
- TODO: Documentation
+outgoing_calls() *vim.lsp.buf.outgoing_calls()*
+ Lists all the items that are called by the symbol under the
+ cursor in the |quickfix| window. If the symbol can resolve to
+ multiple items, the user can pick one in the |inputlist|.
*vim.lsp.buf.range_formatting()*
range_formatting({options}, {start_pos}, {end_pos})
- TODO: Documentation
+ Perform |vim.lsp.buf.formatting()| synchronously.
+
+ Useful for running on save, to make sure buffer is formatted
+ prior to being saved. {timeout_ms} is passed on to
+ |vim.lsp.buf_request_sync()|.
+
+ Parameters: ~
+ {options} Table with valid `FormattingOptions` entries
+ {timeout_ms} (number) Request timeout
references({context}) *vim.lsp.buf.references()*
Lists all the references to the symbol under the cursor in the
quickfix window.
+ Parameters: ~
+ {context} (table) Context for the request
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
+
rename({new_name}) *vim.lsp.buf.rename()*
- Renames all references to the symbol under the cursor. If
- {new_name} is not provided, the user will be prompted for a
- new name using |input()|.
+ Renames all references to the symbol under the cursor.
-request({method}, {params}, {callback}) *vim.lsp.buf.request()*
- TODO: Documentation
+ Parameters: ~
+ {new_name} (string) If not provided, the user will be
+ prompted for a new name using |input()|.
server_ready() *vim.lsp.buf.server_ready()*
+ Checks whether the language servers attached to the current
+ buffer are ready.
+
Return: ~
`true` if server responds.
@@ -846,115 +836,75 @@ workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()*
Lists all symbols in the current workspace in the quickfix
window.
- The list is filtered against the optional argument {query}; if
- the argument is omitted from the call, the user is prompted to
- enter a string on the command line. An empty string means no
- filtering is done.
+ The list is filtered against {query}; if the argument is
+ omitted from the call, the user is prompted to enter a string
+ on the command line. An empty string means no filtering is
+ done.
-incoming_calls() *vim.lsp.buf.incoming_calls()*
- Lists all the call sites of the symbol under the cursor in the
- |quickfix| window. If the symbol can resolve to multiple
- items, the user can pick one in the |inputlist|.
-
-outgoing_calls() *vim.lsp.buf.outgoing_calls()*
- Lists all the items that are called by the symbol under the
- cursor in the |quickfix| window. If the symbol can resolve to
- multiple items, the user can pick one in the |inputlist|.
-
-
-==============================================================================
-Lua module: vim.lsp.callbacks *lsp-callbacks*
-
-err_message({...}) *vim.lsp.callbacks.err_message()*
- TODO: Documentation
-
- *vim.lsp.callbacks.location_callback()*
-location_callback({_}, {method}, {result})
- TODO: Documentation
+ Parameters: ~
+ {query} (string, optional)
==============================================================================
Lua module: vim.lsp.log *lsp-log*
get_filename() *vim.lsp.log.get_filename()*
- TODO: Documentation
+ Returns the log filename.
-path_join({...}) *vim.lsp.log.path_join()*
- TODO: Documentation
+ Return: ~
+ (string) log filename
set_level({level}) *vim.lsp.log.set_level()*
- TODO: Documentation
-
-should_log({level}) *vim.lsp.log.should_log()*
- TODO: Documentation
-
-
-==============================================================================
-Lua module: vim.lsp.rpc *lsp-rpc*
+ Sets the current log level.
-convert_NIL({v}) *vim.lsp.rpc.convert_NIL()*
- TODO: Documentation
-
- *vim.lsp.rpc.create_and_start_client()*
-create_and_start_client({cmd}, {cmd_args}, {handlers},
- {extra_spawn_params})
- TODO: Documentation
+ Parameters: ~
+ {level} (string or number) One of `vim.lsp.log.levels`
-encode_and_send({payload}) *vim.lsp.rpc.encode_and_send()*
- TODO: Documentation
+should_log({level}) *vim.lsp.log.should_log()*
+ Checks whether the level is sufficient for logging.
-env_merge({env}) *vim.lsp.rpc.env_merge()*
- Merges current process env with the given env and returns the
- result as a list of "k=v" strings.
->
+ Parameters: ~
+ {level} number log level
- Example:
-<
+ Return: ~
+ (bool) true if would log, false if not
- > in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", }
- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", }
-<
- *vim.lsp.rpc.format_message_with_content_length()*
-format_message_with_content_length({encoded_message})
- TODO: Documentation
+==============================================================================
+Lua module: vim.lsp.rpc *lsp-rpc*
format_rpc_error({err}) *vim.lsp.rpc.format_rpc_error()*
- TODO: Documentation
-
-handle_body({body}) *vim.lsp.rpc.handle_body()*
- TODO: Documentation
-
-is_dir({filename}) *vim.lsp.rpc.is_dir()*
- TODO: Documentation
+ Constructs an error message from an LSP error object.
-json_decode({data}) *vim.lsp.rpc.json_decode()*
- TODO: Documentation
-
-json_encode({data}) *vim.lsp.rpc.json_encode()*
- TODO: Documentation
+ Parameters: ~
+ {err} (table) The error object
-notification({method}, {params}) *vim.lsp.rpc.notification()*
- TODO: Documentation
+ Return: ~
+ (string) The formatted error message
-on_error({errkind}, {...}) *vim.lsp.rpc.on_error()*
- TODO: Documentation
+notify({method}, {params}) *vim.lsp.rpc.notify()*
+ Sends a notification to the LSP server.
-on_exit({code}, {signal}) *vim.lsp.rpc.on_exit()*
- TODO: Documentation
+ Parameters: ~
+ {method} (string) The invoked LSP method
+ {params} (table): Parameters for the invoked LSP method
-onexit({code}, {signal}) *vim.lsp.rpc.onexit()*
- TODO: Documentation
+ Return: ~
+ (bool) `true` if notification could be sent, `false` if
+ not
-parse_headers({header}) *vim.lsp.rpc.parse_headers()*
- TODO: Documentation
+request({method}, {params}, {callback}) *vim.lsp.rpc.request()*
+ Sends a request to the LSP server and runs {callback} upon
+ response.
- *vim.lsp.rpc.pcall_handler()*
-pcall_handler({errkind}, {status}, {head}, {...})
- TODO: Documentation
+ Parameters: ~
+ {method} (string) The invoked LSP method
+ {params} (table) Parameters for the invoked LSP method
+ {callback} (function) Callback to invoke
-request_parser_loop() *vim.lsp.rpc.request_parser_loop()*
- TODO: Documentation
+ Return: ~
+ (bool, number) `(true, message_id)` if request could be
+ sent, `false` if not
*vim.lsp.rpc.rpc_response_error()*
rpc_response_error({code}, {message}, {data})
@@ -966,48 +916,84 @@ rpc_response_error({code}, {message}, {data})
{message} (optional) arbitrary message to send to server
{data} (optional) arbitrary data to send to server
-send_notification({method}, {params}) *vim.lsp.rpc.send_notification()*
- TODO: Documentation
+ *vim.lsp.rpc.start()*
+start({cmd}, {cmd_args}, {handlers}, {extra_spawn_params})
+ Start an LSP server process and create an LSP RPC client
+ object to interact with it.
- *vim.lsp.rpc.send_request()*
-send_request({method}, {params}, {callback})
- TODO: Documentation
-
- *vim.lsp.rpc.send_response()*
-send_response({request_id}, {err}, {result})
- TODO: Documentation
+ Parameters: ~
+ {cmd} (string) Command to start the LSP
+ server.
+ {cmd_args} (table) List of additional string
+ arguments to pass to {cmd}.
+ {handlers} (table, optional) Handlers for LSP
+ message types. Valid handler names
+ are:
+ • `"notification"`
+ • `"server_request"`
+ • `"on_error"`
+ • `"on_exit"`
+ {extra_spawn_params} (table, optional) Additional context
+ for the LSP server process. May
+ contain:
+ • {cwd} (string) Working directory
+ for the LSP server process
+ • {env} (table) Additional
+ environment variables for LSP
+ server process
-server_request({method}, {params}) *vim.lsp.rpc.server_request()*
- TODO: Documentation
+ Return: ~
+ Client RPC object.
+ Methods:
+ • `notify()` |vim.lsp.rpc.notify()|
+ • `request()` |vim.lsp.rpc.request()|
-try_call({errkind}, {fn}, {...}) *vim.lsp.rpc.try_call()*
- TODO: Documentation
+ Members:
+ • {pid} (number) The LSP server's PID.
+ • {handle} A handle for low-level interaction with the LSP
+ server process |vim.loop|.
==============================================================================
Lua module: vim.lsp.util *lsp-util*
- *vim.lsp.util.apply_syntax_to_region()*
-apply_syntax_to_region({ft}, {start}, {finish})
- TODO: Documentation
-
*vim.lsp.util.apply_text_document_edit()*
apply_text_document_edit({text_document_edit})
- TODO: Documentation
+ Apply a `TextDocumentEdit` , which is a list of changes to a
+ single document.
+
+ Parameters: ~
+ {text_document_edit} (table) a `TextDocumentEdit` object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
*vim.lsp.util.apply_text_edits()*
apply_text_edits({text_edits}, {bufnr})
- TODO: Documentation
+ Applies a list of text edits to a buffer.
+
+ Parameters: ~
+ {text_edits} (table) list of `TextEdit` objects
+ {buf_nr} (number) Buffer id
*vim.lsp.util.apply_workspace_edit()*
apply_workspace_edit({workspace_edit})
- TODO: Documentation
+ Applies a `WorkspaceEdit` .
+
+ Parameters: ~
+ {workspace_edit} (table) `WorkspaceEdit`
buf_clear_diagnostics({bufnr}) *vim.lsp.util.buf_clear_diagnostics()*
- TODO: Documentation
+ Clear diagnostics for a buffer.
+
+ Parameters: ~
+ {bufnr} (number) buffer id
buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
- TODO: Documentation
+ Removes document highlights from a buffer.
+
+ Parameters: ~
+ {bufnr} buffer id
buf_diagnostics_count({kind}) *vim.lsp.util.buf_diagnostics_count()*
Returns the number of diagnostics of given kind for current
@@ -1040,12 +1026,14 @@ buf_diagnostics_count({kind}) *vim.lsp.util.buf_diagnostics_count()*
*vim.lsp.util.buf_diagnostics_save_positions()*
buf_diagnostics_save_positions({bufnr}, {diagnostics})
- Saves the diagnostics (Diagnostic[]) into diagnostics_by_buf
+ Saves diagnostics into
+ vim.lsp.util.diagnostics_by_buf[{bufnr}].
Parameters: ~
- {bufnr} bufnr for which the diagnostics are for.
- {diagnostics} Diagnostics[] received from the language
- server.
+ {bufnr} (number) buffer id for which the
+ diagnostics are for
+ {diagnostics} list of `Diagnostic` s received from the
+ LSP server
*vim.lsp.util.buf_diagnostics_signs()*
buf_diagnostics_signs({bufnr}, {diagnostics})
@@ -1061,38 +1049,117 @@ buf_diagnostics_signs({bufnr}, {diagnostics})
*vim.lsp.util.buf_diagnostics_underline()*
buf_diagnostics_underline({bufnr}, {diagnostics})
- TODO: Documentation
+ Highlights a list of diagnostics in a buffer by underlining
+ them.
+
+ Parameters: ~
+ {bufnr} (number) buffer id
+ {diagnostics} (list of `Diagnostic` s)
*vim.lsp.util.buf_diagnostics_virtual_text()*
buf_diagnostics_virtual_text({bufnr}, {diagnostics})
- TODO: Documentation
+ Given a list of diagnostics, set the corresponding virtual
+ text for a buffer.
+
+ Parameters: ~
+ {bufnr} buffer id
+ {diagnostics} (table) list of `Diagnostic` s
*vim.lsp.util.buf_highlight_references()*
buf_highlight_references({bufnr}, {references})
- TODO: Documentation
+ Show a list of document highlights for a certain buffer.
+
+ Parameters: ~
+ {bufnr} buffer id
+ {references} List of `DocumentHighlight` objects to
+ highlight
character_offset({buf}, {row}, {col}) *vim.lsp.util.character_offset()*
- TODO: Documentation
+ Returns the UTF-32 and UTF-16 offsets for a position in a
+ certain buffer.
+
+ Parameters: ~
+ {buf} buffer id (0 for current)
+ {row} 0-indexed line
+ {col} 0-indexed byte offset in line
+
+ Return: ~
+ (number, number) UTF-32 and UTF-16 index of the character
+ in line {row} column {col} in buffer {buf}
*vim.lsp.util.close_preview_autocmd()*
close_preview_autocmd({events}, {winnr})
- TODO: Documentation
+ Create autocommands to close a preview window when events
+ happen.
+
+ Parameters: ~
+ {events} (table) list of events
+ {winnr} (number) window id of preview window
+
+ See also: ~
+ |autocmd-events|
*vim.lsp.util.convert_input_to_markdown_lines()*
convert_input_to_markdown_lines({input}, {contents})
- TODO: Documentation
+ Convert any of `MarkedString` | `MarkedString[]` |
+ `MarkupContent` into a list of lines containing valid
+ markdown. Useful to populate the hover window for
+ `textDocument/hover` , for parsing the result of
+ `textDocument/signatureHelp` , and potentially others.
+
+ Parameters: ~
+ {input} ( `MarkedString` | `MarkedString[]` |
+ `MarkupContent` )
+ {contents} (table, optional, default `{}` ) List of
+ strings to extend with converted lines
+
+ Return: ~
+ {contents}, extended with lines of converted markdown.
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
*vim.lsp.util.convert_signature_help_to_markdown_lines()*
convert_signature_help_to_markdown_lines({signature_help})
- TODO: Documentation
+ Convert `textDocument/SignatureHelp` response to markdown
+ lines.
+
+ Parameters: ~
+ {signature_help} Response of `textDocument/SignatureHelp`
+
+ Return: ~
+ list of lines of converted markdown.
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
*vim.lsp.util.diagnostics_group_by_line()*
diagnostics_group_by_line({diagnostics})
- TODO: Documentation
+ Groups a list of diagnostics by line.
+
+ Parameters: ~
+ {diagnostics} (table) list of `Diagnostic` s
+
+ Return: ~
+ (table) dictionary mapping lines to lists of diagnostics
+ valid on those lines
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
*vim.lsp.util.extract_completion_items()*
extract_completion_items({result})
- TODO: Documentation
+ Can be used to extract the completion items from a `textDocument/completion` request, which may return one of `CompletionItem[]` , `CompletionList` or null.
+
+ Parameters: ~
+ {result} (table) The result of a
+ `textDocument/completion` request
+
+ Return: ~
+ (table) List of completion items
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
*vim.lsp.util.fancy_floating_markdown()*
fancy_floating_markdown({contents}, {opts})
@@ -1100,8 +1167,7 @@ fancy_floating_markdown({contents}, {opts})
the code blocks and converting them into highlighted code.
This will by default insert a blank line separator after those
code block regions to improve readability. The result is shown
- in a floating preview TODO: refactor to separate
- stripping/converting and make use of open_floating_preview
+ in a floating preview
Parameters: ~
{contents} table of lines to show in window
@@ -1110,22 +1176,34 @@ fancy_floating_markdown({contents}, {opts})
Return: ~
width,height size of float
-find_window_by_var({name}, {value}) *vim.lsp.util.find_window_by_var()*
- TODO: Documentation
-
focusable_float({unique_name}, {fn}) *vim.lsp.util.focusable_float()*
- TODO: Documentation
+ Parameters: ~
+ {unique_name} (string) Window variable
+ {fn} (function) should return create a new
+ window and return a tuple of
+ ({focusable_buffer_id}, {window_id}). if
+ {focusable_buffer_id} is a valid buffer id,
+ the newly created window will be the new
+ focus associated with the current buffer
+ via the tag `unique_name` .
+
+ Return: ~
+ (pbufnr, pwinnr) if `fn()` has created a new window; nil
+ otherwise
*vim.lsp.util.focusable_preview()*
focusable_preview({unique_name}, {fn})
- TODO: Documentation
-
-get_completion_word({item}) *vim.lsp.util.get_completion_word()*
- TODO: Documentation
+ Focus/unfocus the floating preview window associated with the
+ current buffer via the window variable `unique_name` . If no
+ such preview window exists, make a new one.
- *vim.lsp.util.get_current_line_to_cursor()*
-get_current_line_to_cursor()
- TODO: Documentation
+ Parameters: ~
+ {unique_name} (string) Window variable
+ {fn} (function) The return values of this
+ function will be passed directly to
+ |vim.lsp.util.open_floating_preview()|, in
+ the case that a new floating window should
+ be created
get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
Get visual width of tabstop.
@@ -1140,48 +1218,104 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
See also: ~
|softtabstop|
- *vim.lsp.util.get_line_byte_from_position()*
-get_line_byte_from_position({bufnr}, {position})
- TODO: Documentation
-
get_line_diagnostics() *vim.lsp.util.get_line_diagnostics()*
- TODO: Documentation
+ Get list of diagnostics for the current line.
+
+ Return: ~
+ (table) list of `Diagnostic` tables
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
*vim.lsp.util.get_severity_highlight_name()*
get_severity_highlight_name({severity})
- TODO: Documentation
+ Get the name of a severity's highlight group.
+
+ Parameters: ~
+ {severity} A member of
+ `vim.lsp.protocol.DiagnosticSeverity`
+
+ Return: ~
+ (string) Highlight group name
jump_to_location({location}) *vim.lsp.util.jump_to_location()*
- TODO: Documentation
+ Jumps to a location.
+
+ Parameters: ~
+ {location} ( `Location` | `LocationLink` )
+
+ Return: ~
+ `true` if the jump succeeded
locations_to_items({locations}) *vim.lsp.util.locations_to_items()*
- TODO: Documentation
+ Returns the items with the byte position calculated correctly
+ and in sorted order, for display in quickfix and location
+ lists.
+
+ Parameters: ~
+ {locations} (table) list of `Location` s or
+ `LocationLink` s
+
+ Return: ~
+ (table) list of items
*vim.lsp.util.make_floating_popup_options()*
make_floating_popup_options({width}, {height}, {opts})
- TODO: Documentation
+ Creates a table with sensible default options for a floating
+ window. The table can be passed to |nvim_open_win()|.
+
+ Parameters: ~
+ {width} (number) window width (in character cells)
+ {height} (number) window height (in character cells)
+ {opts} (table, optional)
+
+ Return: ~
+ (table) Options
*vim.lsp.util.make_formatting_params()*
make_formatting_params({options})
- TODO: Documentation
+ Creates a `FormattingOptions` object for the current buffer
+ and cursor position.
-make_position_param() *vim.lsp.util.make_position_param()*
- TODO: Documentation
+ Parameters: ~
+ {options} Table with valid `FormattingOptions` entries
+
+ Return: ~
+ `FormattingOptions object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
make_position_params() *vim.lsp.util.make_position_params()*
- TODO: Documentation
+ Creates a `TextDocumentPositionParams` object for the current
+ buffer and cursor position.
+
+ Return: ~
+ `TextDocumentPositionParams` object
+
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
make_range_params() *vim.lsp.util.make_range_params()*
- TODO: Documentation
+ Using the current position in the current buffer, creates an
+ object that can be used as a building block for several LSP
+ requests, such as `textDocument/codeAction` ,
+ `textDocument/colorPresentation` ,
+ `textDocument/rangeFormatting` .
+
+ Return: ~
+ { textDocument = { uri = `current_file_uri` }, range = {
+ start = `current_position` , end = `current_position` } }
make_text_document_params() *vim.lsp.util.make_text_document_params()*
- TODO: Documentation
+ Creates a `TextDocumentIdentifier` object for the current
+ buffer.
-npcall({fn}, {...}) *vim.lsp.util.npcall()*
- TODO: Documentation
+ Return: ~
+ `TextDocumentIdentifier`
-ok_or_nil({status}, {...}) *vim.lsp.util.ok_or_nil()*
- TODO: Documentation
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
*vim.lsp.util.open_floating_preview()*
open_floating_preview({contents}, {filetype}, {opts})
@@ -1193,17 +1327,20 @@ open_floating_preview({contents}, {filetype}, {opts})
{opts} dictionary with optional fields
Return: ~
- bufnr,winnr buffer and window number of floating window or
- nil
+ bufnr,winnr buffer and window number of the newly created
+ floating preview window
parse_snippet({input}) *vim.lsp.util.parse_snippet()*
- TODO: Documentation
+ Parses snippets in a completion entry.
-parse_snippet_rec({input}, {inner}) *vim.lsp.util.parse_snippet_rec()*
- TODO: Documentation
+ Parameters: ~
+ {input} (string) unparsed snippet
+
+ Return: ~
+ (string) parsed snippet
preview_location({location}) *vim.lsp.util.preview_location()*
- Preview a location in a floating windows
+ Preview a location in a floating window
behavior depends on type of location:
• for Location, range is shown (e.g., function definition)
@@ -1211,36 +1348,45 @@ preview_location({location}) *vim.lsp.util.preview_location()*
function definition)
Parameters: ~
- {location} a single Location or LocationLink
+ {location} a single `Location` or `LocationLink`
Return: ~
- bufnr,winnr buffer and window number of floating window or
- nil
-
- *vim.lsp.util.remove_unmatch_completion_items()*
-remove_unmatch_completion_items({items}, {prefix})
- TODO: Documentation
+ (bufnr,winnr) buffer and window number of floating window
+ or nil
set_lines({lines}, {A}, {B}, {new_lines}) *vim.lsp.util.set_lines()*
- TODO: Documentation
+ Replace text in a range with new text.
-set_loclist({items}) *vim.lsp.util.set_loclist()*
- TODO: Documentation
+ CAUTION: Changes in-place!
-set_qflist({items}) *vim.lsp.util.set_qflist()*
- TODO: Documentation
+ Parameters: ~
+ {lines} (table) Original list of strings
+ {A} (table) Start position; a 2-tuple of {line,
+ col} numbers
+ {B} (table) End position; a 2-tuple of {line,
+ col} numbers
+ {new_lines} A list of strings to replace the original
-show_line_diagnostics() *vim.lsp.util.show_line_diagnostics()*
- TODO: Documentation
+ Return: ~
+ (table) The modified {lines} object
-sort_by_key({fn}) *vim.lsp.util.sort_by_key()*
- TODO: Documentation
+set_loclist({items}) *vim.lsp.util.set_loclist()*
+ Fills current window's location list with given list of items.
+ Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
-sort_completion_items({items}) *vim.lsp.util.sort_completion_items()*
- TODO: Documentation
+ Parameters: ~
+ {items} (table) list of items
-split_lines({value}) *vim.lsp.util.split_lines()*
- TODO: Documentation
+set_qflist({items}) *vim.lsp.util.set_qflist()*
+ Fills quickfix list with given list of items. Can be obtained
+ with e.g. |vim.lsp.util.locations_to_items()|.
+
+ Parameters: ~
+ {items} (table) list of items
+
+show_line_diagnostics() *vim.lsp.util.show_line_diagnostics()*
+ Displays the diagnostics for the current line in a floating
+ hover window.
symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()*
Convert symbols to quickfix list items
@@ -1250,13 +1396,43 @@ symbols_to_items({symbols}, {bufnr}) *vim.lsp.util.symbols_to_items()*
*vim.lsp.util.text_document_completion_list_to_complete_items()*
text_document_completion_list_to_complete_items({result}, {prefix})
- TODO: Documentation
+ Turns the result of a `textDocument/completion` request into
+ vim-compatible |complete-items|.
+
+ Parameters: ~
+ {result} The result of a `textDocument/completion` call,
+ e.g. from |vim.lsp.buf.completion()|, which may
+ be one of `CompletionItem[]` , `CompletionList`
+ or `null`
+ {prefix} (string) the prefix to filter the completion
+ items
+
+ Return: ~
+ { matches = complete-items table, incomplete = bool }
+
+ See also: ~
+ |complete-items|
trim_empty_lines({lines}) *vim.lsp.util.trim_empty_lines()*
- TODO: Documentation
+ Remove empty lines from the beginning and end.
+
+ Parameters: ~
+ {lines} (table) list of lines to trim
+
+ Return: ~
+ (table) trimmed list of lines
*vim.lsp.util.try_trim_markdown_code_blocks()*
try_trim_markdown_code_blocks({lines})
- TODO: Documentation
+ Accepts markdown lines and tries to reduce them to a filetype
+ if they comprise just a single code block.
+
+ CAUTION: Modifies the input in-place!
+
+ Parameters: ~
+ {lines} (table) list of lines
+
+ Return: ~
+ (string) filetype or 'markdown' if it was unchanged.
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 6fe1d15b7e..9d7ab9b74f 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -27,11 +27,21 @@ local lsp = {
-- TODO improve handling of scratch buffers with LSP attached.
+--@private
+--- Concatenates and writes a list of strings to the Vim error buffer.
+---
+--@param {...} (List of strings) List to write to the buffer
local function err_message(...)
nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
nvim_command("redraw")
end
+--@private
+--- Returns the buffer number for the given {bufnr}.
+---
+--@param bufnr (number) Buffer number to resolve. Defaults to the current
+---buffer if not given.
+--@returns bufnr (number) Number of requested buffer
local function resolve_bufnr(bufnr)
validate { bufnr = { bufnr, 'n', true } }
if bufnr == nil or bufnr == 0 then
@@ -40,6 +50,11 @@ local function resolve_bufnr(bufnr)
return bufnr
end
+--@private
+--- Checks whether a given path is a directory.
+---
+--@param filename (string) path to check
+--@returns true if {filename} exists and is a directory, false otherwise
local function is_dir(filename)
validate{filename={filename,'s'}}
local stat = uv.fs_stat(filename)
@@ -55,6 +70,10 @@ local valid_encodings = {
}
local client_index = 0
+--@private
+--- Returns a new, unused client id.
+---
+--@returns (number) client id
local function next_client_id()
client_index = client_index + 1
return client_index
@@ -64,6 +83,12 @@ local active_clients = {}
local all_buffer_active_clients = {}
local uninitialized_clients = {}
+--@private
+--- Invokes a callback for each LSP client attached to the buffer {bufnr}.
+---
+--@param bufnr (Number) of buffer
+--@param callback (function({client}, {client_id}, {bufnr}) Function to run on
+---each client attached to that buffer.
local function for_each_buffer_client(bufnr, callback)
validate {
callback = { callback, 'f' };
@@ -88,6 +113,11 @@ lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_rever
ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1;
})
+--@private
+--- Normalizes {encoding} to valid LSP encoding names.
+---
+--@param encoding (string) Encoding to normalize
+--@returns (string) normalized encoding name
local function validate_encoding(encoding)
validate {
encoding = { encoding, 's' };
@@ -96,6 +126,13 @@ local function validate_encoding(encoding)
or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding))
end
+--@internal
+--- Parses a command invocation into the command itself and its args. If there
+--- are no arguments, an empty table is returned as the second argument.
+---
+--@param input (List)
+--@returns (string) the command
+--@returns (list of strings) its arguments
function lsp._cmd_parts(input)
vim.validate{cmd={
input,
@@ -114,12 +151,27 @@ function lsp._cmd_parts(input)
return cmd, cmd_args
end
+--@private
+--- Augments a validator function with support for optional (nil) values.
+---
+--@param fn (function(v)) The original validator function; should return a
+---bool.
+--@returns (function(v)) The augmented function. Also returns true if {v} is
+---`nil`.
local function optional_validator(fn)
return function(v)
return v == nil or fn(v)
end
end
+--@private
+--- Validates a client configuration as given to |vim.lsp.start_client()|.
+---
+--@param config (table)
+--@returns (table) "Cleaned" config, containing only the command, its
+---arguments, and a valid encoding.
+---
+--@see |vim.lsp.start_client()|
local function validate_client_config(config)
validate {
config = { config, 't' };
@@ -148,6 +200,11 @@ local function validate_client_config(config)
}
end
+--@private
+--- Returns full text of buffer {bufnr} as a string.
+---
+--@param bufnr (number) Buffer handle, or 0 for current.
+--@returns Buffer text as string.
local function buf_get_full_text(bufnr)
local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n')
if nvim_buf_get_option(bufnr, 'eol') then
@@ -156,6 +213,11 @@ local function buf_get_full_text(bufnr)
return text
end
+--@private
+--- Default handler for the 'textDocument/didOpen' LSP notification.
+---
+--@param bufnr (Number) Number of the buffer, or 0 for current
+--@param client Client object
local function text_document_did_open_handler(bufnr, client)
if not client.resolved_capabilities.text_document_open_close then
return
@@ -176,74 +238,88 @@ local function text_document_did_open_handler(bufnr, client)
util.buf_versions[bufnr] = params.textDocument.version
end
---- LSP client object.
+--- LSP client object. You can get an active client object via
+--- |vim.lsp.get_client_by_id()| or |vim.lsp.get_active_clients()|.
---
--- - Methods:
---
---- - request(method, params, [callback])
---- Send a request to the server. If callback is not specified, it will use
---- {client.callbacks} to try to find a callback. If one is not found there,
---- then an error will occur.
+--- - request(method, params, [callback], bufnr)
+--- Sends a request to the server.
--- This is a thin wrapper around {client.rpc.request} with some additional
--- checking.
---- Returns a boolean to indicate if the notification was successful. If it
---- is false, then it will always be false (the client has shutdown).
---- If it was successful, then it will return the request id as the second
---- result. You can use this with `notify("$/cancel", { id = request_id })`
---- to cancel the request. This helper is made automatically with
---- |vim.lsp.buf_request()|
---- Returns: status, [client_id]
+--- If {callback} is not specified, it will use {client.callbacks} to try to
+--- find a callback. If one is not found there, then an error will occur.
+--- Returns: {status}, {[client_id]}. {status} is a boolean indicating if
+--- the notification was successful. If it is `false`, then it will always
+--- be `false` (the client has shutdown).
+--- If {status} is `true`, the function returns {request_id} as the second
+--- result. You can use this with `client.cancel_request(request_id)`
+--- to cancel the request.
---
--- - notify(method, params)
---- This is just {client.rpc.notify}()
---- Returns a boolean to indicate if the notification was successful. If it
---- is false, then it will always be false (the client has shutdown).
---- Returns: status
+--- Sends a notification to an LSP server.
+--- Returns: a boolean to indicate if the notification was successful. If
+--- it is false, then it will always be false (the client has shutdown).
---
--- - cancel_request(id)
---- This is just {client.rpc.notify}("$/cancelRequest", { id = id })
---- Returns the same as `notify()`.
+--- Cancels a request with a given request id.
+--- Returns: same as `notify()`.
---
--- - stop([force])
---- Stop a client, optionally with force.
+--- Stops a client, optionally with force.
--- By default, it will just ask the server to shutdown without force.
--- If you request to stop a client which has previously been requested to
--- shutdown, it will automatically escalate and force shutdown.
---
--- - is_stopped()
---- Returns true if the client is fully stopped.
+--- Checks whether a client is stopped.
+--- Returns: true if the client is fully stopped.
+---
+--- - on_attach(bufnr)
+--- Runs the on_attach function from the client's config if it was defined.
---
--- - Members
---- - id (number): The id allocated to the client.
+--- - {id} (number): The id allocated to the client.
---
---- - name (string): If a name is specified on creation, that will be
+--- - {name} (string): If a name is specified on creation, that will be
--- used. Otherwise it is just the client id. This is used for
--- logs and messages.
---
---- - offset_encoding (string): The encoding used for communicating
---- with the server. You can modify this in the `on_init` method
+--- - {rpc} (table): RPC client object, for low level interaction with the
+--- client. See |vim.lsp.rpc.start()|.
+---
+--- - {offset_encoding} (string): The encoding used for communicating
+--- with the server. You can modify this in the `config`'s `on_init` method
--- before text is sent to the server.
---
---- - callbacks (table): The callbacks used by the client as
+--- - {callbacks} (table): The callbacks used by the client as
--- described in |lsp-callbacks|.
---
---- - config (table): copy of the table that was passed by the user
+--- - {config} (table): copy of the table that was passed by the user
--- to |vim.lsp.start_client()|.
---
---- - server_capabilities (table): Response from the server sent on
+--- - {server_capabilities} (table): Response from the server sent on
--- `initialize` describing the server's capabilities.
---
---- - resolved_capabilities (table): Normalized table of
+--- - {resolved_capabilities} (table): Normalized table of
--- capabilities that we have detected based on the initialize
--- response from the server in `server_capabilities`.
function lsp.client()
error()
end
+-- FIXME: Currently all methods on the `vim.lsp.client` object are documented
+-- twice: Here, and on the methods themselves (e.g. `client.request()`). This
+-- is a workaround for the vimdoc generator script not handling method names
+-- correctly. If you change the documentation on either, please make sure to
+-- update the other as well.
+
--- Starts and initializes a client with the given configuration.
---
--- Parameters `cmd` and `root_dir` are required.
---
+--- The following parameters describe fields in the {config} table.
+---
--@param root_dir: (required, string) Directory where the LSP server will base
--- its rootUri on initialization.
---
@@ -271,8 +347,8 @@ end
---
--@param callbacks Map of language server method names to
--- `function(err, method, params, client_id)` handler. Invoked for:
---- - Notifications from the server, where `err` will always be `nil`.
---- - Requests initiated by the server. For these you can respond by returning
+--- - Notifications to the server, where `err` will always be `nil`.
+--- - Requests by the server. For these you can respond by returning
--- two values: `result, err` where err must be shaped like a RPC error,
--- i.e. `{ code, message, data? }`. Use |vim.lsp.rpc_response_error()| to
--- help with this.
@@ -297,7 +373,7 @@ end
--@param before_init Callback with parameters (initialize_params, config)
--- invoked before the LSP "initialize" phase, where `params` contains the
--- parameters being sent to the server and `config` is the config that was
---- passed to `start_client()`. You can use this to modify parameters before
+--- passed to |vim.lsp.start_client()|. You can use this to modify parameters before
--- they are sent.
---
--@param on_init Callback (client, initialize_result) invoked after LSP
@@ -335,10 +411,23 @@ function lsp.start_client(config)
local handlers = {}
+ --@private
+ --- Returns the callback associated with an LSP method. Returns the default
+ --- callback if the user hasn't set a custom one.
+ ---
+ --@param method (string) LSP method name
+ --@returns (fn) The callback for the given method, if defined, or the default
+ ---from |lsp-callbacks|
local function resolve_callback(method)
return callbacks[method] or default_callbacks[method]
end
+ --@private
+ --- Handles a notification sent by an LSP server by invoking the
+ --- corresponding callback.
+ ---
+ --@param method (string) LSP method name
+ --@param params (table) The parameters for that method.
function handlers.notification(method, params)
local _ = log.debug() and log.debug('notification', method, params)
local callback = resolve_callback(method)
@@ -348,6 +437,12 @@ function lsp.start_client(config)
end
end
+ --@private
+ --- Handles a request from an LSP server by invoking the corresponding
+ --- callback.
+ ---
+ --@param method (string) LSP method name
+ --@param params (table) The parameters for that method
function handlers.server_request(method, params)
local _ = log.debug() and log.debug('server_request', method, params)
local callback = resolve_callback(method)
@@ -359,6 +454,13 @@ function lsp.start_client(config)
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
+ --@private
+ --- Invoked when the client operation throws an error.
+ ---
+ --@param code (number) Error code
+ --@param err (...) Other arguments may be passed depending on the error kind
+ --@see |vim.lsp.client_errors| for possible errors. Use
+ ---`vim.lsp.client_errors[code]` to get a human-friendly name.
function handlers.on_error(code, err)
local _ = log.error() and log.error(log_prefix, "on_error", { code = lsp.client_errors[code], err = err })
err_message(log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err))
@@ -371,6 +473,11 @@ function lsp.start_client(config)
end
end
+ --@private
+ --- Invoked on client exit.
+ ---
+ --@param code (number) exit code of the process
+ --@param signal (number) the signal used to terminate (if any)
function handlers.on_exit(code, signal)
active_clients[client_id] = nil
uninitialized_clients[client_id] = nil
@@ -411,6 +518,7 @@ function lsp.start_client(config)
-- initialize finishes.
uninitialized_clients[client_id] = client;
+ --@private
local function initialize()
local valid_traces = {
off = 'off'; messages = 'messages'; verbose = 'verbose';
@@ -488,6 +596,12 @@ function lsp.start_client(config)
end)
end
+ --@private
+ --- Throws error for a method that is not supported by the current LSP
+ --- server.
+ ---
+ --@param method (string) an LSP method name not supported by the LSP server.
+ --@returns (error) a 'MethodNotFound' JSON-RPC error response.
local function unsupported_method(method)
local msg = "server doesn't support "..method
local _ = log.warn() and log.warn(msg)
@@ -495,8 +609,28 @@ function lsp.start_client(config)
return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
end
- --- Checks capabilities before rpc.request-ing.
+ --@private
+ --- Sends a request to the server.
+ ---
+ --- This is a thin wrapper around {client.rpc.request} with some additional
+ --- checks for capabilities and callback availability.
+ ---
+ --@param method (string) LSP method name.
+ --@param params (table) LSP request params.
+ --@param callback (function, optional) Response handler for this method.
+ ---If {callback} is not specified, it will use {client.callbacks} to try to
+ ---find a callback. If one is not found there, then an error will occur.
+ --@param bufnr (number) Buffer handle (0 for current).
+ --@returns ({status}, [request_id]): {status} is a bool indicating
+ ---whether the request was successful. If it is `false`, then it will
+ ---always be `false` (the client has shutdown). If it was
+ ---successful, then it will return {request_id} as the
+ ---second result. You can use this with `client.cancel_request(request_id)`
+ ---to cancel the-request.
+ --@see |vim.lsp.buf_request()|
function client.request(method, params, callback, bufnr)
+ -- FIXME: callback is optional, but bufnr is apparently not? Shouldn't that
+ -- require a `select('#', ...)` call?
if not callback then
callback = resolve_callback(method)
or error(string.format("not found: %q request callback for client %q.", method, client.name))
@@ -521,10 +655,25 @@ function lsp.start_client(config)
end)
end
+ --@private
+ --- Sends a notification to an LSP server.
+ ---
+ --@param method (string) LSP method name.
+ --@param params (optional, table) LSP request params.
+ --@param bufnr (number) Buffer handle, or 0 for current.
+ --@returns {status} (bool) true if the notification was successful.
+ ---If it is false, then it will always be false
+ ---(the client has shutdown).
function client.notify(...)
return rpc.notify(...)
end
+ --@private
+ --- Cancels a request with a given request id.
+ ---
+ --@param id (number) id of request to cancel
+ --@returns true if any client returns true; false otherwise
+ --@see |vim.lsp.client.notify()|
function client.cancel_request(id)
validate{id = {id, 'n'}}
return rpc.notify("$/cancelRequest", { id = id })
@@ -533,6 +682,14 @@ function lsp.start_client(config)
-- Track this so that we can escalate automatically if we've alredy tried a
-- graceful shutdown
local tried_graceful_shutdown = false
+ --@private
+ --- Stops a client, optionally with force.
+ ---
+ ---By default, it will just ask the - server to shutdown without force. If
+ --- you request to stop a client which has previously been requested to
+ --- shutdown, it will automatically escalate and force shutdown.
+ ---
+ --@param force (bool, optional)
function client.stop(force)
local handle = rpc.handle
if handle:is_closing() then
@@ -554,10 +711,18 @@ function lsp.start_client(config)
end)
end
+ --@private
+ --- Checks whether a client is stopped.
+ ---
+ --@returns (bool) true if client is stopped or in the process of being
+ ---stopped; false otherwise
function client.is_stopped()
return rpc.handle:is_closing()
end
+ --@private
+ --- Runs the on_attach function from the client's config if it was defined.
+ --@param bufnr (number) Buffer number
function client._on_attach(bufnr)
text_document_did_open_handler(bufnr, client)
if config.on_attach then
@@ -571,6 +736,12 @@ function lsp.start_client(config)
return client_id
end
+--@private
+--- Memoizes a function. On first run, the function return value is saved and
+--- immediately returned on subsequent runs.
+---
+--@param fn (function) Function to run
+--@returns (function) Memoized function
local function once(fn)
local value
return function(...)
@@ -579,6 +750,9 @@ local function once(fn)
end
end
+--@private
+--@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size)
+--- Notify all attached clients that a buffer has changed.
local text_document_did_change_handler
do
local encoding_index = { ["utf-8"] = 1; ["utf-16"] = 2; ["utf-32"] = 3; }
@@ -735,7 +909,7 @@ end
---
--@param client_id client id number
---
---@return |vim.lsp.client| object, or nil
+--@returns |vim.lsp.client| object, or nil
function lsp.get_client_by_id(client_id)
return active_clients[client_id]
end
@@ -769,7 +943,7 @@ end
--- Gets all active clients.
---
---@return Table of |vim.lsp.client| objects
+--@returns Table of |vim.lsp.client| objects
function lsp.get_active_clients()
return vim.tbl_values(active_clients)
end
@@ -904,7 +1078,7 @@ end
--@param findstart 0 or 1, decides behavior
--@param base If findstart=0, text to match against
---
---@return (number) Decided by `findstart`:
+--@returns (number) Decided by `findstart`:
--- - findstart=0: column where the completion starts, or -2 or -3
--- - findstart=1: list of matches (actually just calls |complete()|)
function lsp.omnifunc(findstart, base)
@@ -948,6 +1122,10 @@ function lsp.omnifunc(findstart, base)
return -2
end
+---Checks whether a client is stopped.
+---
+--@param client_id (Number)
+--@returns true if client is stopped, false otherwise.
function lsp.client_is_stopped(client_id)
return active_clients[client_id] == nil
end
@@ -992,12 +1170,17 @@ function lsp.set_log_level(level)
end
--- Gets the path of the logfile used by the LSP client.
+--@returns (String) Path to logfile.
function lsp.get_log_path()
return log.get_filename()
end
--- Define the LspDiagnostics signs if they're not defined already.
+-- Defines the LspDiagnostics signs if they're not defined already.
do
+ --@private
+ --- Defines a sign if it isn't already defined.
+ --@param name (String) Name of the sign
+ --@param properties (table) Properties to attach to the sign
local function define_default_sign(name, properties)
if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
vim.fn.sign_define(name, properties)
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 2e27617997..208082f241 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -7,14 +7,41 @@ local list_extend = vim.list_extend
local M = {}
+--@private
+--- Returns nil if {status} is false or nil, otherwise returns the rest of the
+--- arguments.
local function ok_or_nil(status, ...)
if not status then return end
return ...
end
+
+--@private
+--- Swallows errors.
+---
+--@param fn Function to run
+--@param ... Function arguments
+--@returns Result of `fn(...)` if there are no errors, otherwise nil.
+--- Returns nil if errors occur during {fn}, otherwise returns
local function npcall(fn, ...)
return ok_or_nil(pcall(fn, ...))
end
+--@private
+--- Sends an async request to all active clients attached to the current
+--- buffer.
+---
+--@param method (string) LSP method name
+--@param params (optional, table) Parameters to send to the server
+--@param callback (optional, functionnil) Handler
+-- `function(err, method, params, client_id)` for this request. Defaults
+-- to the client callback in `client.callbacks`. See |lsp-callbacks|.
+--
+--@returns 2-tuple:
+--- - Map of client-id:request-id pairs for all successful requests.
+--- - Function which can be used to cancel all the requests. You could instead
+--- iterate all clients and call their `cancel_request()` methods.
+---
+--@see |vim.lsp.buf_request()|
local function request(method, params, callback)
validate {
method = {method, 's'};
@@ -23,9 +50,10 @@ local function request(method, params, callback)
return vim.lsp.buf_request(0, method, params, callback)
end
---- Sends a notification through all clients associated with current buffer.
---
---@return `true` if server responds.
+--- Checks whether the language servers attached to the current buffer are
+--- ready.
+---
+--@returns `true` if server responds.
function M.server_ready()
return not not vim.lsp.buf_notify(0, "window/progress", {})
end
@@ -74,6 +102,12 @@ end
--- Retrieves the completion items at the current cursor position. Can only be
--- called in Insert mode.
+---
+--@param context (context support not yet implemented) Additional information
+--- about the context in which a completion was triggered (how it was triggered,
+--- and by which trigger character, if applicable)
+---
+--@see |vim.lsp.protocol.constants.CompletionTriggerKind|
function M.completion(context)
local params = util.make_position_params()
params.context = context
@@ -82,20 +116,27 @@ end
--- Formats the current buffer.
---
---- The optional {options} table can be used to specify FormattingOptions, a
---- list of which is available at
---- https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting.
+--@param options (optional, table) Can be used to specify FormattingOptions.
--- Some unspecified options will be automatically derived from the current
--- Neovim options.
+--
+--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
function M.formatting(options)
local params = util.make_formatting_params(options)
return request('textDocument/formatting', params)
end
---- Perform |vim.lsp.buf.formatting()| synchronously.
+--- Performs |vim.lsp.buf.formatting()| synchronously.
---
--- Useful for running on save, to make sure buffer is formatted prior to being
---- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|.
+--- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|. Example:
+---
+--- <pre>
+--- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]]
+--- </pre>
+---
+--@param options Table with valid `FormattingOptions` entries
+--@param timeout_ms (number) Request timeout
function M.formatting_sync(options, timeout_ms)
local params = util.make_formatting_params(options)
local result = vim.lsp.buf_request_sync(0, "textDocument/formatting", params, timeout_ms)
@@ -104,6 +145,13 @@ function M.formatting_sync(options, timeout_ms)
vim.lsp.util.apply_text_edits(result)
end
+--- Formats a given range.
+---
+--@param options Table with valid `FormattingOptions` entries.
+--@param start_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the start of the last visual selection.
+--@param start_pos ({number, number}, optional) mark-indexed position.
+---Defaults to the end of the last visual selection.
function M.range_formatting(options, start_pos, end_pos)
validate {
options = {options, 't', true};
@@ -138,8 +186,10 @@ function M.range_formatting(options, start_pos, end_pos)
return request('textDocument/rangeFormatting', params)
end
---- Renames all references to the symbol under the cursor. If {new_name} is not
---- provided, the user will be prompted for a new name using |input()|.
+--- Renames all references to the symbol under the cursor.
+---
+--@param new_name (string) If not provided, the user will be prompted for a new
+---name using |input()|.
function M.rename(new_name)
-- TODO(ashkan) use prepareRename
-- * result: [`Range`](#range) \| `{ range: Range, placeholder: string }` \| `null` describing the range of the string to rename and optionally a placeholder text of the string content to be renamed. If `null` is returned then it is deemed that a 'textDocument/rename' request is not valid at the given position.
@@ -152,6 +202,8 @@ end
--- Lists all the references to the symbol under the cursor in the quickfix window.
---
+--@param context (table) Context for the request
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
function M.references(context)
validate { context = { context, 't', true } }
local params = util.make_position_params()
@@ -169,6 +221,7 @@ function M.document_symbol()
request('textDocument/documentSymbol', params)
end
+--@private
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then return end
if #call_hierarchy_items == 1 then
@@ -186,6 +239,9 @@ local function pick_call_hierarchy_item(call_hierarchy_items)
return choice
end
+--- Lists all the call sites of the symbol under the cursor in the
+--- |quickfix| window. If the symbol can resolve to multiple
+--- items, the user can pick one in the |inputlist|.
function M.incoming_calls()
local params = util.make_position_params()
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
@@ -194,6 +250,9 @@ function M.incoming_calls()
end)
end
+--- Lists all the items that are called by the symbol under the
+--- cursor in the |quickfix| window. If the symbol can resolve to
+--- multiple items, the user can pick one in the |inputlist|.
function M.outgoing_calls()
local params = util.make_position_params()
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
@@ -204,9 +263,11 @@ end
--- Lists all symbols in the current workspace in the quickfix window.
---
---- The list is filtered against the optional argument {query};
---- if the argument is omitted from the call, the user is prompted to enter a string on the command line.
---- An empty string means no filtering is done.
+--- The list is filtered against {query}; if the argument is omitted from the
+--- call, the user is prompted to enter a string on the command line. An empty
+--- string means no filtering is done.
+---
+--@param query (string, optional)
function M.workspace_symbol(query)
query = query or npcall(vfn.input, "Query: ")
local params = {query = query}
@@ -227,10 +288,17 @@ function M.document_highlight()
request('textDocument/documentHighlight', params)
end
+--- Removes document highlights from current buffer.
+---
function M.clear_references()
util.buf_clear_references()
end
+--- Selects a code action from the input list that is available at the current
+--- cursor position.
+--
+--@param context: (table, optional) Valid `CodeActionContext` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
function M.code_action(context)
validate { context = { context, 't', true } }
context = context or { diagnostics = util.get_line_diagnostics() }
@@ -239,6 +307,10 @@ function M.code_action(context)
request('textDocument/codeAction', params)
end
+--- Executes an LSP server command.
+---
+--@param command A valid `ExecuteCommandParams` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
function M.execute_command(command)
validate {
command = { command.command, 's' },
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index 1ed58995d0..9920af0124 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -7,17 +7,22 @@ local buf = require 'vim.lsp.buf'
local M = {}
+--@private
+--- Writes to error buffer.
+--@param ... (table of strings) Will be concatenated before being written
local function err_message(...)
api.nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
api.nvim_command("redraw")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
M['workspace/executeCommand'] = function(err, _)
if err then
error("Could not execute code action: "..err.message)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
M['textDocument/codeAction'] = function(_, _, actions)
if actions == nil or vim.tbl_isempty(actions) then
print("No code actions available")
@@ -51,6 +56,7 @@ M['textDocument/codeAction'] = function(_, _, actions)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
M['workspace/applyEdit'] = function(_, _, workspace_edit)
if not workspace_edit then return end
-- TODO(ashkan) Do something more with label?
@@ -64,6 +70,7 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit)
}
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_publishDiagnostics
M['textDocument/publishDiagnostics'] = function(_, _, result)
if not result then return end
local uri = result.uri
@@ -102,6 +109,7 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
vim.api.nvim_command("doautocmd User LspDiagnosticsChanged")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
M['textDocument/references'] = function(_, _, result)
if not result then return end
util.set_qflist(util.locations_to_items(result))
@@ -109,6 +117,13 @@ M['textDocument/references'] = function(_, _, result)
api.nvim_command("wincmd p")
end
+--@private
+--- Prints given list of symbols to the quickfix list.
+--@param _ (not used)
+--@param _ (not used)
+--@param result (list of Symbols) LSP method name
+--@param result (table) result of LSP method; a location or a list of locations.
+---(`textDocument/definition` can return `Location` or `Location[]`
local symbol_callback = function(_, _, result, _, bufnr)
if not result or vim.tbl_isempty(result) then return end
@@ -116,24 +131,30 @@ local symbol_callback = function(_, _, result, _, bufnr)
api.nvim_command("copen")
api.nvim_command("wincmd p")
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
M['textDocument/documentSymbol'] = symbol_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
M['workspace/symbol'] = symbol_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
M['textDocument/rename'] = function(_, _, result)
if not result then return end
util.apply_workspace_edit(result)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
M['textDocument/rangeFormatting'] = function(_, _, result)
if not result then return end
util.apply_text_edits(result)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
M['textDocument/formatting'] = function(_, _, result)
if not result then return end
util.apply_text_edits(result)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
M['textDocument/completion'] = function(_, _, result)
if vim.tbl_isempty(result or {}) then return end
local row, col = unpack(api.nvim_win_get_cursor(0))
@@ -146,6 +167,7 @@ M['textDocument/completion'] = function(_, _, result)
vim.fn.complete(textMatch+1, matches)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
M['textDocument/hover'] = function(_, method, result)
util.focusable_float(method, function()
if not (result and result.contents) then
@@ -166,6 +188,12 @@ M['textDocument/hover'] = function(_, method, result)
end)
end
+--@private
+--- Jumps to a location. Used as a callback for multiple LSP methods.
+--@param _ (not used)
+--@param method (string) LSP method name
+--@param result (table) result of LSP method; a location or a list of locations.
+---(`textDocument/definition` can return `Location` or `Location[]`
local function location_callback(_, method, result)
if result == nil or vim.tbl_isempty(result) then
local _ = log.info() and log.info(method, 'No location found')
@@ -188,11 +216,16 @@ local function location_callback(_, method, result)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration
M['textDocument/declaration'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
M['textDocument/definition'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition
M['textDocument/typeDefinition'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation
M['textDocument/implementation'] = location_callback
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
M['textDocument/signatureHelp'] = function(_, method, result)
util.focusable_preview(method, function()
if not (result and result.signatures and result.signatures[1]) then
@@ -208,15 +241,21 @@ M['textDocument/signatureHelp'] = function(_, method, result)
end)
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
M['textDocument/documentHighlight'] = function(_, _, result, _)
if not result then return end
local bufnr = api.nvim_get_current_buf()
util.buf_highlight_references(bufnr, result)
end
--- direction is "from" for incoming calls and "to" for outgoing calls
+--@private
+---
+--- Displays call hierarchy in the quickfix window.
+---
+--@param direction `"from"` for incoming calls and `"to"` for outgoing calls
+--@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`,
+--@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`,
local make_call_hierarchy_callback = function(direction)
- -- result is a CallHierarchy{Incoming,Outgoing}Call[]
return function(_, _, result)
if not result then return end
local items = {}
@@ -237,10 +276,13 @@ local make_call_hierarchy_callback = function(direction)
end
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/incomingCalls
M['callHierarchy/incomingCalls'] = make_call_hierarchy_callback('from')
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/outgoingCalls
M['callHierarchy/outgoingCalls'] = make_call_hierarchy_callback('to')
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/logMessage
M['window/logMessage'] = function(_, _, result, client_id)
local message_type = result.type
local message = result.message
@@ -261,6 +303,7 @@ M['window/logMessage'] = function(_, _, result, client_id)
return result
end
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/showMessage
M['window/showMessage'] = function(_, _, result, client_id)
local message_type = result.type
local message = result.message
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 696ce43a59..f19367851f 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -21,12 +21,14 @@ local log_date_format = "%FT%H:%M:%S%z"
do
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
+ --@private
local function path_join(...)
return table.concat(vim.tbl_flatten{...}, path_sep)
end
local logfilename = path_join(vim.fn.stdpath('data'), 'lsp.log')
- --- Return the log filename.
+ --- Returns the log filename.
+ --@returns (string) log filename
function log.get_filename()
return logfilename
end
@@ -74,6 +76,8 @@ end
-- interfere with iterating the levels
vim.tbl_add_reverse_lookup(log.levels)
+--- Sets the current log level.
+--@param level (string or number) One of `vim.lsp.log.levels`
function log.set_level(level)
if type(level) == 'string' then
current_log_level = assert(log.levels[level:upper()], string.format("Invalid log level: %q", level))
@@ -84,8 +88,9 @@ function log.set_level(level)
end
end
--- Return whether the level is sufficient for logging.
--- @param level number log level
+--- Checks whether the level is sufficient for logging.
+--@param level number log level
+--@returns (bool) true if would log, false if not
function log.should_log(level)
return level >= current_log_level
end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index ef5e08680e..4e926381e0 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -2,6 +2,11 @@
local protocol = {}
+--@private
+--- Returns {a} if it is not nil, otherwise returns {b}.
+---
+--@param a
+--@param b
local function ifnil(a, b)
if a == nil then return b end
return a
@@ -9,12 +14,14 @@ end
--[=[
--- Useful for interfacing with:
--- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
+--@private
+--- Useful for interfacing with:
+--- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
function transform_schema_comments()
nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]]
nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]]
end
+--@private
function transform_schema_to_table()
transform_schema_comments()
nvim.command [[silent! '<,'>s/: \S\+//]]
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 81c92bfe05..8ed09bf34a 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -5,6 +5,11 @@ local protocol = require('vim.lsp.protocol')
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
-- TODO replace with a better implementation.
+--@private
+--- Encodes to JSON.
+---
+--@param data (table) Data to encode
+--@returns (string) Encoded object
local function json_encode(data)
local status, result = pcall(vim.fn.json_encode, data)
if status then
@@ -13,6 +18,11 @@ local function json_encode(data)
return nil, result
end
end
+--@private
+--- Decodes from JSON.
+---
+--@param data (string) Data to decode
+--@returns (table) Decoded JSON object
local function json_decode(data)
local status, result = pcall(vim.fn.json_decode, data)
if status then
@@ -22,17 +32,26 @@ local function json_decode(data)
end
end
+--@private
+--- Checks whether a given path exists and is a directory.
+--@param filename (string) path to check
+--@returns (bool)
local function is_dir(filename)
local stat = vim.loop.fs_stat(filename)
return stat and stat.type == 'directory' or false
end
local NIL = vim.NIL
+--@private
+--- Returns its argument, but converts `vim.NIL` to Lua `nil`.
+--@param v (any) Argument
+--@returns (any)
local function convert_NIL(v)
if v == NIL then return nil end
return v
end
+--@private
--- Merges current process env with the given env and returns the result as
--- a list of "k=v" strings.
---
@@ -42,6 +61,8 @@ end
--- in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", }
--- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", }
--- </pre>
+--@param env (table) table of environment variable assignments
+--@returns (table) list of `"k=v"` strings
local function env_merge(env)
if env == nil then
return env
@@ -56,6 +77,11 @@ local function env_merge(env)
return final_env
end
+--@private
+--- Embeds the given string into a table and correctly computes `Content-Length`.
+---
+--@param encoded_message (string)
+--@returns (table) table containing encoded message and `Content-Length` attribute
local function format_message_with_content_length(encoded_message)
return table.concat {
'Content-Length: '; tostring(#encoded_message); '\r\n\r\n';
@@ -63,8 +89,11 @@ local function format_message_with_content_length(encoded_message)
}
end
---- Parse an LSP Message's header
--- @param header: The header to parse.
+--@private
+--- Parses an LSP Message's header
+---
+--@param header: The header to parse.
+--@returns Parsed headers
local function parse_headers(header)
if type(header) ~= 'string' then
return nil
@@ -92,6 +121,8 @@ end
-- case insensitive pattern.
local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end)
+--@private
+--- The actual workhorse.
local function request_parser_loop()
local buffer = ''
while true do
@@ -138,6 +169,10 @@ local client_errors = vim.tbl_add_reverse_lookup {
SERVER_RESULT_CALLBACK_ERROR = 7;
}
+--- Constructs an error message from an LSP error object.
+---
+--@param err (table) The error object
+--@returns (string) The formatted error message
local function format_rpc_error(err)
validate {
err = { err, 't' };
@@ -182,23 +217,69 @@ local function rpc_response_error(code, message, data)
end
local default_handlers = {}
+--@private
+--- Default handler for notifications sent to an LSP server.
+---
+--@param method (string) The invoked LSP method
+--@param params (table): Parameters for the invoked LSP method
function default_handlers.notification(method, params)
local _ = log.debug() and log.debug('notification', method, params)
end
+--@private
+--- Default handler for requests sent to an LSP server.
+---
+--@param method (string) The invoked LSP method
+--@param params (table): Parameters for the invoked LSP method
+--@returns `nil` and `vim.lsp.protocol.ErrorCodes.MethodNotFound`.
function default_handlers.server_request(method, params)
local _ = log.debug() and log.debug('server_request', method, params)
return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
+--@private
+--- Default handler for when a client exits.
+---
+--@param code (number): Exit code
+--@param signal (number): Number describing the signal used to terminate (if
+---any)
function default_handlers.on_exit(code, signal)
- local _ = log.info() and log.info("client exit", { code = code, signal = signal })
+ local _ = log.info() and log.info("client_exit", { code = code, signal = signal })
end
+--@private
+--- Default handler for client errors.
+---
+--@param code (number): Error code
+--@param err (any): Details about the error
+---any)
function default_handlers.on_error(code, err)
local _ = log.error() and log.error('client_error:', client_errors[code], err)
end
---- Create and start an RPC client.
--- @param cmd [
-local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_params)
+--- Starts an LSP server process and create an LSP RPC client object to
+--- interact with it.
+---
+--@param cmd (string) Command to start the LSP server.
+--@param cmd_args (table) List of additional string arguments to pass to {cmd}.
+--@param handlers (table, optional) Handlers for LSP message types. Valid
+---handler names are:
+--- - `"notification"`
+--- - `"server_request"`
+--- - `"on_error"`
+--- - `"on_exit"`
+--@param extra_spawn_params (table, optional) Additional context for the LSP
+--- server process. May contain:
+--- - {cwd} (string) Working directory for the LSP server process
+--- - {env} (table) Additional environment variables for LSP server process
+--@returns Client RPC object.
+---
+--@returns Methods:
+--- - `notify()` |vim.lsp.rpc.notify()|
+--- - `request()` |vim.lsp.rpc.request()|
+---
+--@returns Members:
+--- - {pid} (number) The LSP server's PID.
+--- - {handle} A handle for low-level interaction with the LSP server process
+--- |vim.loop|.
+local function start(cmd, cmd_args, handlers, extra_spawn_params)
local _ = log.info() and log.info("Starting RPC client", {cmd = cmd, args = cmd_args, extra = extra_spawn_params})
validate {
cmd = { cmd, 's' };
@@ -242,6 +323,11 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
local handle, pid
do
+ --@private
+ --- Callback for |vim.loop.spawn()| Closes all streams and runs the
+ --- `on_exit` handler.
+ --@param code (number) Exit code
+ --@param signal (number) Signal that was used to terminate (if any)
local function onexit(code, signal)
stdin:close()
stdout:close()
@@ -265,6 +351,12 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
handle, pid = uv.spawn(cmd, spawn_params, onexit)
end
+ --@private
+ --- Encodes {payload} into a JSON-RPC message and sends it to the remote
+ --- process.
+ ---
+ --@param payload (table) Converted into a JSON string, see |json_encode()|
+ --@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing.
local function encode_and_send(payload)
local _ = log.debug() and log.debug("rpc.send.payload", payload)
if handle:is_closing() then return false end
@@ -276,7 +368,12 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
return true
end
- local function send_notification(method, params)
+ -- FIXME: Should be placed on the RPC client object returned by `start()`
+ --- Sends a notification to the LSP server.
+ --@param method (string) The invoked LSP method
+ --@param params (table): Parameters for the invoked LSP method
+ --@returns (bool) `true` if notification could be sent, `false` if not
+ local function notify(method, params)
local _ = log.debug() and log.debug("rpc.notify", method, params)
return encode_and_send {
jsonrpc = "2.0";
@@ -285,6 +382,8 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
}
end
+ --@private
+ --- sends an error object to the remote LSP process.
local function send_response(request_id, err, result)
return encode_and_send {
id = request_id;
@@ -294,7 +393,14 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
}
end
- local function send_request(method, params, callback)
+ -- FIXME: Should be placed on the RPC client object returned by `start()`
+ --- Sends a request to the LSP server and runs {callback} upon response.
+ ---
+ --@param method (string) The invoked LSP method
+ --@param params (table) Parameters for the invoked LSP method
+ --@param callback (function) Callback to invoke
+ --@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not
+ local function request(method, params, callback)
validate {
callback = { callback, 'f' };
}
@@ -320,11 +426,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
end
end)
+ --@private
local function on_error(errkind, ...)
assert(client_errors[errkind])
-- TODO what to do if this fails?
pcall(handlers.on_error, errkind, ...)
end
+ --@private
local function pcall_handler(errkind, status, head, ...)
if not status then
on_error(errkind, head, ...)
@@ -332,6 +440,7 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
end
return status, head, ...
end
+ --@private
local function try_call(errkind, fn, ...)
return pcall_handler(errkind, pcall(fn, ...))
end
@@ -340,6 +449,7 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
-- time and log them. This would require storing the timestamp. I could call
-- them with an error then, perhaps.
+ --@private
local function handle_body(body)
local decoded, err = json_decode(body)
if not decoded then
@@ -458,13 +568,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
return {
pid = pid;
handle = handle;
- request = send_request;
- notify = send_notification;
+ request = request;
+ notify = notify
}
end
return {
- start = create_and_start_client;
+ start = start;
rpc_response_error = rpc_response_error;
format_rpc_error = format_rpc_error;
client_errors = client_errors;
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 33fca29ecd..7e94de7ec3 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -7,6 +7,7 @@ local highlight = require 'vim.highlight'
local M = {}
+-- FIXME: Expose in documentation
--- Diagnostics received from the server via `textDocument/publishDiagnostics`
-- by buffer.
--
@@ -33,18 +34,30 @@ local M = {}
M.diagnostics_by_buf = {}
local split = vim.split
+--@private
local function split_lines(value)
return split(value, '\n', true)
end
+--@private
local function ok_or_nil(status, ...)
if not status then return end
return ...
end
+--@private
local function npcall(fn, ...)
return ok_or_nil(pcall(fn, ...))
end
+--- Replaces text in a range with new text.
+---
+--- CAUTION: Changes in-place!
+---
+--@param lines (table) Original list of strings
+--@param A (table) Start position; a 2-tuple of {line, col} numbers
+--@param B (table) End position; a 2-tuple of {line, col} numbers
+--@param new_lines A list of strings to replace the original
+--@returns (table) The modified {lines} object
function M.set_lines(lines, A, B, new_lines)
-- 0-indexing to 1-indexing
local i_0 = A[1] + 1
@@ -78,6 +91,7 @@ function M.set_lines(lines, A, B, new_lines)
return lines
end
+--@private
local function sort_by_key(fn)
return function(a,b)
local ka, kb = fn(a), fn(b)
@@ -91,13 +105,15 @@ local function sort_by_key(fn)
return false
end
end
+--@private
local edit_sort_key = sort_by_key(function(e)
return {e.A[1], e.A[2], e.i}
end)
+--@private
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
--- Returns a zero-indexed column, since set_lines() does the conversion to
--- 1-indexed
+--- Returns a zero-indexed column, since set_lines() does the conversion to
+--- 1-indexed
local function get_line_byte_from_position(bufnr, position)
-- LSP's line and characters are 0-indexed
-- Vim's line and columns are 1-indexed
@@ -114,6 +130,9 @@ local function get_line_byte_from_position(bufnr, position)
return col
end
+--- Applies a list of text edits to a buffer.
+--@param text_edits (table) list of `TextEdit` objects
+--@param buf_nr (number) Buffer id
function M.apply_text_edits(text_edits, bufnr)
if not next(text_edits) then return end
if not api.nvim_buf_is_loaded(bufnr) then
@@ -168,20 +187,30 @@ end
-- function M.glob_to_regex(glob)
-- end
--- textDocument/completion response returns one of CompletionItem[], CompletionList or null.
--- https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
+--- Can be used to extract the completion items from a
+--- `textDocument/completion` request, which may return one of
+--- `CompletionItem[]`, `CompletionList` or null.
+--@param result (table) The result of a `textDocument/completion` request
+--@returns (table) List of completion items
+--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
function M.extract_completion_items(result)
if type(result) == 'table' and result.items then
+ -- result is a `CompletionList`
return result.items
elseif result ~= nil then
+ -- result is `CompletionItem[]`
return result
else
+ -- result is `null`
return {}
end
end
---- Apply the TextDocumentEdit response.
--- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification
+--- Applies a `TextDocumentEdit`, which is a list of changes to a single
+-- document.
+---
+--@param text_document_edit (table) a `TextDocumentEdit` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit)
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
@@ -195,6 +224,13 @@ function M.apply_text_document_edit(text_document_edit)
M.apply_text_edits(text_document_edit.edits, bufnr)
end
+--@private
+--- Recursively parses snippets in a completion entry.
+---
+--@param input (string) Snippet text to parse for snippets
+--@param inner (bool) Whether this function is being called recursively
+--@returns 2-tuple of strings: The first is the parsed result, the second is the
+---unparsed rest of the input
local function parse_snippet_rec(input, inner)
local res = ""
@@ -248,15 +284,20 @@ local function parse_snippet_rec(input, inner)
return res, input
end
--- Parse completion entries, consuming snippet tokens
+--- Parses snippets in a completion entry.
+---
+--@param input (string) unparsed snippet
+--@returns (string) parsed snippet
function M.parse_snippet(input)
local res, _ = parse_snippet_rec(input, false)
return res
end
--- Sort by CompletionItem.sortText
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--@private
+--- Sorts by CompletionItem.sortText.
+---
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function sort_completion_items(items)
if items[1] and items[1].sortText then
table.sort(items, function(a, b) return a.sortText < b.sortText
@@ -264,9 +305,10 @@ local function sort_completion_items(items)
end
end
--- Returns text that should be inserted when selecting completion item. The precedence is as follows:
--- textEdit.newText > insertText > label
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--@private
+--- Returns text that should be inserted when selecting completion item. The
+--- precedence is as follows: textEdit.newText > insertText > label
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function get_completion_word(item)
if item.textEdit ~= nil and item.textEdit.newText ~= nil then
if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
@@ -284,8 +326,10 @@ local function get_completion_word(item)
return item.label
end
--- Some language servers return complementary candidates whose prefixes do not match are also returned.
--- So we exclude completion candidates whose prefix does not match.
+--@private
+--- Some language servers return complementary candidates whose prefixes do not
+--- match are also returned. So we exclude completion candidates whose prefix
+--- does not match.
local function remove_unmatch_completion_items(items, prefix)
return vim.tbl_filter(function(item)
local word = get_completion_word(item)
@@ -293,16 +337,26 @@ local function remove_unmatch_completion_items(items, prefix)
end, items)
end
--- Acording to LSP spec, if the client set "completionItemKind.valueSet",
--- the client must handle it properly even if it receives a value outside the specification.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--- Acording to LSP spec, if the client set `completionItemKind.valueSet`,
+--- the client must handle it properly even if it receives a value outside the
+--- specification.
+---
+--@param completion_item_kind (`vim.lsp.protocol.completionItemKind`)
+--@returns (`vim.lsp.protocol.completionItemKind`)
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
function M._get_completion_item_kind_name(completion_item_kind)
return protocol.CompletionItemKind[completion_item_kind] or "Unknown"
end
---- Getting vim complete-items with incomplete flag.
--- @params CompletionItem[], CompletionList or nil (https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
--- @return { matches = complete-items table, incomplete = boolean }
+--- Turns the result of a `textDocument/completion` request into vim-compatible
+--- |complete-items|.
+---
+--@param result The result of a `textDocument/completion` call, e.g. from
+---|vim.lsp.buf.completion()|, which may be one of `CompletionItem[]`,
+--- `CompletionList` or `null`
+--@param prefix (string) the prefix to filter the completion items
+--@returns { matches = complete-items table, incomplete = bool }
+--@see |complete-items|
function M.text_document_completion_list_to_complete_items(result, prefix)
local items = M.extract_completion_items(result)
if vim.tbl_isempty(items) then
@@ -350,7 +404,10 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
return matches
end
--- @params WorkspaceEdit [table] see https://microsoft.github.io/language-server-protocol/specification
+--- Applies a `WorkspaceEdit`.
+---
+--@param workspace_edit (table) `WorkspaceEdit`
+-- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit)
if workspace_edit.documentChanges then
for _, change in ipairs(workspace_edit.documentChanges) do
@@ -375,9 +432,15 @@ function M.apply_workspace_edit(workspace_edit)
end
end
---- Convert any of MarkedString | MarkedString[] | MarkupContent into markdown text lines
--- see https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_hover
--- Useful for textDocument/hover, textDocument/signatureHelp, and potentially others.
+--- Converts any of `MarkedString` | `MarkedString[]` | `MarkupContent` into
+--- a list of lines containing valid markdown. Useful to populate the hover
+--- window for `textDocument/hover`, for parsing the result of
+--- `textDocument/signatureHelp`, and potentially others.
+---
+--@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
+--@param contents (table, optional, default `{}`) List of strings to extend with converted lines
+--@returns {contents}, extended with lines of converted markdown.
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
-- MarkedString variation 1
@@ -416,8 +479,11 @@ function M.convert_input_to_markdown_lines(input, contents)
return contents
end
---- Convert SignatureHelp response to markdown lines.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
+--- Converts `textDocument/SignatureHelp` response to markdown lines.
+---
+--@param signature_help Response of `textDocument/SignatureHelp`
+--@returns list of lines of converted markdown.
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
function M.convert_signature_help_to_markdown_lines(signature_help)
if not signature_help.signatures then
return
@@ -475,6 +541,13 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
return contents
end
+--- Creates a table with sensible default options for a floating window. The
+--- table can be passed to |nvim_open_win()|.
+---
+--@param width (number) window width (in character cells)
+--@param height (number) window height (in character cells)
+--@param opts (table, optional)
+--@returns (table) Options
function M.make_floating_popup_options(width, height, opts)
validate {
opts = { opts, 't', true };
@@ -520,6 +593,10 @@ function M.make_floating_popup_options(width, height, opts)
}
end
+--- Jumps to a location.
+---
+--@param location (`Location`|`LocationLink`)
+--@returns `true` if the jump succeeded
function M.jump_to_location(location)
-- location may be Location or LocationLink
local uri = location.uri or location.targetUri
@@ -543,14 +620,14 @@ function M.jump_to_location(location)
return true
end
---- Preview a location in a floating windows
+--- Previews a location in a floating window
---
--- behavior depends on type of location:
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
---@param location a single Location or LocationLink
---@return bufnr,winnr buffer and window number of floating window or nil
+--@param location a single `Location` or `LocationLink`
+--@returns (bufnr,winnr) buffer and window number of floating window or nil
function M.preview_location(location)
-- location may be LocationLink or Location (more useful for the former)
local uri = location.targetUri or location.uri
@@ -565,6 +642,7 @@ function M.preview_location(location)
return M.open_floating_preview(contents, filetype)
end
+--@private
local function find_window_by_var(name, value)
for _, win in ipairs(api.nvim_list_wins()) do
if npcall(api.nvim_win_get_var, win, name) == value then
@@ -573,12 +651,18 @@ local function find_window_by_var(name, value)
end
end
--- Check if a window with `unique_name` tagged is associated with the current
--- buffer. If not, make a new preview.
---
--- fn()'s return bufnr, winnr
--- case that a new floating window should be created.
+--- Enters/leaves the focusable window associated with the current buffer via the
+--window - variable `unique_name`. If no such window exists, run the function
+--{fn}.
+---
+--@param unique_name (string) Window variable
+--@param fn (function) should return create a new window and return a tuple of
+---({focusable_buffer_id}, {window_id}). if {focusable_buffer_id} is a valid
+---buffer id, the newly created window will be the new focus associated with
+---the current buffer via the tag `unique_name`.
+--@returns (pbufnr, pwinnr) if `fn()` has created a new window; nil otherwise
function M.focusable_float(unique_name, fn)
+ -- Go back to previous window if we are in a focusable one
if npcall(api.nvim_win_get_var, 0, unique_name) then
return api.nvim_command("wincmd p")
end
@@ -598,18 +682,21 @@ function M.focusable_float(unique_name, fn)
end
end
--- Check if a window with `unique_name` tagged is associated with the current
--- buffer. If not, make a new preview.
---
--- fn()'s return values will be passed directly to open_floating_preview in the
--- case that a new floating window should be created.
+--- Focuses/unfocuses the floating preview window associated with the current
+--- buffer via the window variable `unique_name`. If no such preview window
+--- exists, makes a new one.
+---
+--@param unique_name (string) Window variable
+--@param fn (function) The return values of this function will be passed
+---directly to |vim.lsp.util.open_floating_preview()|, in the case that a new
+---floating window should be created
function M.focusable_preview(unique_name, fn)
return M.focusable_float(unique_name, function()
return M.open_floating_preview(fn())
end)
end
---- Trim empty lines from input and pad left and right with spaces
+--- Trims empty lines from input and pad left and right with spaces
---
--@param contents table of lines to trim and pad
--@param opts dictionary with optional fields
@@ -617,7 +704,7 @@ end
-- - pad_right number of columns to pad contents at right (default 1)
-- - pad_top number of lines to pad contents at top (default 0)
-- - pad_bottom number of lines to pad contents at bottom (default 0)
---@return contents table of trimmed and padded lines
+--@returns contents table of trimmed and padded lines
function M._trim_and_pad(contents, opts)
validate {
contents = { contents, 't' };
@@ -645,12 +732,13 @@ end
---- Convert markdown into syntax highlighted regions by stripping the code
+-- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+--
+--- Converts markdown into syntax highlighted regions by stripping the code
--- blocks and converting them into highlighted code.
--- This will by default insert a blank line separator after those code block
--- regions to improve readability.
---- The result is shown in a floating preview
---- TODO: refactor to separate stripping/converting and make use of open_floating_preview
+--- The result is shown in a floating preview.
---
--@param contents table of lines to show in window
--@param opts dictionary with optional fields
@@ -664,7 +752,7 @@ end
-- - pad_top number of lines to pad contents at top
-- - pad_bottom number of lines to pad contents at bottom
-- - separator insert separator after code block
---@return width,height size of float
+--@returns width,height size of float
function M.fancy_floating_markdown(contents, opts)
validate {
contents = { contents, 't' };
@@ -738,6 +826,7 @@ function M.fancy_floating_markdown(contents, opts)
vim.cmd("ownsyntax markdown")
local idx = 1
+ --@private
local function apply_syntax_to_region(ft, start, finish)
if ft == '' then return end
local name = ft..idx
@@ -763,11 +852,17 @@ function M.fancy_floating_markdown(contents, opts)
return bufnr, winnr
end
+--- Creates autocommands to close a preview window when events happen.
+---
+--@param events (table) list of events
+--@param winnr (number) window id of preview window
+--@see |autocmd-events|
function M.close_preview_autocmd(events, winnr)
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
end
---- Compute size of float needed to show contents (with optional wrapping)
+--@internal
+--- Computes size of float needed to show contents (with optional wrapping)
---
--@param contents table of lines to show in window
--@param opts dictionary with optional fields
@@ -776,7 +871,7 @@ end
-- - wrap_at character to wrap at for computing height
-- - max_width maximal width of floating window
-- - max_height maximal height of floating window
---@return width,height size of float
+--@returns width,height size of float
function M._make_floating_popup_size(contents, opts)
validate {
contents = { contents, 't' };
@@ -827,7 +922,7 @@ function M._make_floating_popup_size(contents, opts)
return width, height
end
---- Show contents in a floating window
+--- Shows contents in a floating window.
---
--@param contents table of lines to show in window
--@param filetype string of filetype to set for opened buffer
@@ -841,7 +936,8 @@ end
-- - pad_right number of columns to pad contents at right
-- - pad_top number of lines to pad contents at top
-- - pad_bottom number of lines to pad contents at bottom
---@return bufnr,winnr buffer and window number of floating window or nil
+--@returns bufnr,winnr buffer and window number of the newly created floating
+---preview window
function M.open_floating_preview(contents, filetype, opts)
validate {
contents = { contents, 't' };
@@ -912,6 +1008,9 @@ do
severity_floating_highlights[severity] = floating_highlight_name
end
+ --- Clears diagnostics for a buffer.
+ ---
+ --@param bufnr (number) buffer id
function M.buf_clear_diagnostics(bufnr)
validate { bufnr = {bufnr, 'n', true} }
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
@@ -923,10 +1022,18 @@ do
api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
end
+ --- Gets the name of a severity's highlight group.
+ ---
+ --@param severity A member of `vim.lsp.protocol.DiagnosticSeverity`
+ --@returns (string) Highlight group name
function M.get_severity_highlight_name(severity)
return severity_highlights[severity]
end
+ --- Gets list of diagnostics for the current line.
+ ---
+ --@returns (table) list of `Diagnostic` tables
+ --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
function M.get_line_diagnostics()
local bufnr = api.nvim_get_current_buf()
local linenr = api.nvim_win_get_cursor(0)[1] - 1
@@ -941,6 +1048,8 @@ do
return diagnostics_by_line[linenr] or {}
end
+ --- Displays the diagnostics for the current line in a floating hover
+ --- window.
function M.show_line_diagnostics()
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
-- if #marks == 0 then
@@ -977,10 +1086,10 @@ do
return popup_bufnr, winnr
end
- --- Saves the diagnostics (Diagnostic[]) into diagnostics_by_buf
+ --- Saves diagnostics into vim.lsp.util.diagnostics_by_buf[{bufnr}].
---
- --@param bufnr bufnr for which the diagnostics are for.
- --@param diagnostics Diagnostics[] received from the language server.
+ --@param bufnr (number) buffer id for which the diagnostics are for
+ --@param diagnostics list of `Diagnostic`s received from the LSP server
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
validate {
bufnr = {bufnr, 'n', true};
@@ -1000,6 +1109,10 @@ do
M.diagnostics_by_buf[bufnr] = diagnostics
end
+ --- Highlights a list of diagnostics in a buffer by underlining them.
+ ---
+ --@param bufnr (number) buffer id
+ --@param diagnostics (list of `Diagnostic`s)
function M.buf_diagnostics_underline(bufnr, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range["start"]
@@ -1020,11 +1133,18 @@ do
end
end
+ --- Removes document highlights from a buffer.
+ ---
+ --@param bufnr buffer id
function M.buf_clear_references(bufnr)
validate { bufnr = {bufnr, 'n', true} }
api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
end
+ --- Shows a list of document highlights for a certain buffer.
+ ---
+ --@param bufnr buffer id
+ --@param references List of `DocumentHighlight` objects to highlight
function M.buf_highlight_references(bufnr, references)
validate { bufnr = {bufnr, 'n', true} }
for _, reference in ipairs(references) do
@@ -1040,11 +1160,19 @@ do
end
end
+ --- Groups a list of diagnostics by line.
+ ---
+ --@param diagnostics (table) list of `Diagnostic`s
+ --@returns (table) dictionary mapping lines to lists of diagnostics valid on
+ ---those lines
+ --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
function M.diagnostics_group_by_line(diagnostics)
if not diagnostics then return end
local diagnostics_by_line = {}
for _, diagnostic in ipairs(diagnostics) do
local start = diagnostic.range.start
+ -- TODO: Are diagnostics only valid for a single line? I don't understand
+ -- why this would be okay otherwise
local line_diagnostics = diagnostics_by_line[start.line]
if not line_diagnostics then
line_diagnostics = {}
@@ -1055,6 +1183,11 @@ do
return diagnostics_by_line
end
+ --- Given a list of diagnostics, sets the corresponding virtual text for a
+ --- buffer.
+ ---
+ --@param bufnr buffer id
+ --@param diagnostics (table) list of `Diagnostic`s
function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
if not diagnostics then
return
@@ -1093,8 +1226,7 @@ do
--- </pre>
---
--@param kind Diagnostic severity kind: See |vim.lsp.protocol.DiagnosticSeverity|
- ---
- --@return Count of diagnostics
+ --@returns Count of diagnostics
function M.buf_diagnostics_count(kind)
local bufnr = vim.api.nvim_get_current_buf()
local diagnostics = M.diagnostics_by_buf[bufnr]
@@ -1115,7 +1247,7 @@ do
[protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
}
- --- Place signs for each diagnostic in the sign column.
+ --- Places signs for each diagnostic in the sign column.
---
--- Sign characters can be customized with the following commands:
---
@@ -1136,8 +1268,11 @@ local position_sort = sort_by_key(function(v)
return {v.start.line, v.start.character}
end)
--- Returns the items with the byte position calculated correctly and in sorted
--- order.
+--- Returns the items with the byte position calculated correctly and in sorted
+--- order, for display in quickfix and location lists.
+---
+--@param locations (table) list of `Location`s or `LocationLink`s
+--@returns (table) list of items
function M.locations_to_items(locations)
local items = {}
local grouped = setmetatable({}, {
@@ -1180,6 +1315,10 @@ function M.locations_to_items(locations)
return items
end
+--- Fills current window's location list with given list of items.
+--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
+---
+--@param items (table) list of items
function M.set_loclist(items)
vim.fn.setloclist(0, {}, ' ', {
title = 'Language Server';
@@ -1187,6 +1326,10 @@ function M.set_loclist(items)
})
end
+--- Fills quickfix list with given list of items.
+--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
+---
+--@param items (table) list of items
function M.set_qflist(items)
vim.fn.setqflist({}, ' ', {
title = 'Language Server';
@@ -1201,10 +1344,11 @@ function M._get_symbol_kind_name(symbol_kind)
return protocol.SymbolKind[symbol_kind] or "Unknown"
end
---- Convert symbols to quickfix list items
+--- Converts symbols to quickfix list items.
---
--@param symbols DocumentSymbol[] or SymbolInformation[]
function M.symbols_to_items(symbols, bufnr)
+ --@private
local function _symbols_to_items(_symbols, _items, _bufnr)
for _, symbol in ipairs(_symbols) do
if symbol.location then -- SymbolInformation type
@@ -1239,7 +1383,9 @@ function M.symbols_to_items(symbols, bufnr)
return _symbols_to_items(symbols, {}, bufnr)
end
--- Remove empty lines from the beginning and end.
+--- Removes empty lines from the beginning and end.
+--@param lines (table) list of lines to trim
+--@returns (table) trimmed list of lines
function M.trim_empty_lines(lines)
local start = 1
for i = 1, #lines do
@@ -1258,11 +1404,13 @@ function M.trim_empty_lines(lines)
return vim.list_extend({}, lines, start, finish)
end
--- Accepts markdown lines and tries to reduce it to a filetype if it is
--- just a single code block.
--- Note: This modifies the input.
---
--- Returns: filetype or 'markdown' if it was unchanged.
+--- Accepts markdown lines and tries to reduce them to a filetype if they
+--- comprise just a single code block.
+---
+--- CAUTION: Modifies the input in-place!
+---
+--@param lines (table) list of lines
+--@returns (string) filetype or 'markdown' if it was unchanged.
function M.try_trim_markdown_code_blocks(lines)
local language_id = lines[1]:match("^```(.*)")
if language_id then
@@ -1285,6 +1433,7 @@ function M.try_trim_markdown_code_blocks(lines)
end
local str_utfindex = vim.str_utfindex
+--@private
local function make_position_param()
local row, col = unpack(api.nvim_win_get_cursor(0))
row = row - 1
@@ -1293,6 +1442,10 @@ local function make_position_param()
return { line = row; character = col; }
end
+--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
+---
+--@returns `TextDocumentPositionParams` object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params()
return {
textDocument = M.make_text_document_params();
@@ -1300,6 +1453,13 @@ function M.make_position_params()
}
end
+--- Using the current position in the current buffer, creates an object that
+--- can be used as a building block for several LSP requests, such as
+--- `textDocument/codeAction`, `textDocument/colorPresentation`,
+--- `textDocument/rangeFormatting`.
+---
+--@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---`current_position`, end = `current_position` } }
function M.make_range_params()
local position = make_position_param()
return {
@@ -1308,11 +1468,15 @@ function M.make_range_params()
}
end
+--- Creates a `TextDocumentIdentifier` object for the current buffer.
+---
+--@returns `TextDocumentIdentifier`
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params()
return { uri = vim.uri_from_bufnr(0) }
end
---- Get visual width of tabstop.
+--- Returns visual width of tabstop.
---
--@see |softtabstop|
--@param bufnr (optional, number): Buffer handle, defaults to current
@@ -1324,6 +1488,11 @@ function M.get_effective_tabstop(bufnr)
return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop
end
+--- Creates a `FormattingOptions` object for the current buffer and cursor position.
+---
+--@param options Table with valid `FormattingOptions` entries
+--@returns `FormattingOptions object
+--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
validate { options = {options, 't', true} }
options = vim.tbl_extend('keep', options or {}, {
@@ -1336,9 +1505,12 @@ function M.make_formatting_params(options)
}
end
--- @param buf buffer handle or 0 for current.
--- @param row 0-indexed line
--- @param col 0-indexed byte offset in line
+--- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer.
+---
+--@param buf buffer id (0 for current)
+--@param row 0-indexed line
+--@param col 0-indexed byte offset in line
+--@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(buf, row, col)
local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
-- If the col is past the EOL, use the line length.
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index a61690e99f..f2f003033e 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -960,7 +960,11 @@ def main(config):
i = 0
for filename in CONFIG[target]['section_order']:
- title, helptag, section_doc = sections.pop(filename)
+ try:
+ title, helptag, section_doc = sections.pop(filename)
+ except KeyError:
+ print("Warning:", filename, "has empty docs, skipping")
+ continue
i += 1
if filename not in CONFIG[target]['append_only']:
docs += sep
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index d6f95c7a5f..305d5e6968 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -203,10 +203,10 @@ Integer nvim_get_hl_id_by_name(String name)
/// flags. This is a blocking call, unlike |nvim_input()|.
///
/// On execution error: does not fail, but updates v:errmsg.
-//
-// If you need to input sequences like <C-o> use nvim_replace_termcodes
-// to replace the termcodes and then pass the resulting string to
-// nvim_feedkeys. You'll also want to enable escape_csi.
+///
+/// If you need to input sequences like <C-o> use |nvim_replace_termcodes|
+/// to replace the termcodes and then pass the resulting string to
+/// nvim_feedkeys. You'll also want to enable escape_csi.
///
/// Example:
/// <pre>