mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Add docs for most vim.lsp methods
Most of the lsp.log will be addressed in a separate PR.
This commit is contained in:
parent
8c49e3d509
commit
ac05343a10
@ -734,9 +734,10 @@ nvim_feedkeys({keys}, {mode}, {escape_csi}) *nvim_feedkeys()*
|
|||||||
|
|
||||||
On execution error: does not fail, but updates v:errmsg.
|
On execution error: does not fail, but updates v:errmsg.
|
||||||
|
|
||||||
If you need to input sequences like <C-o> use nvim_replace_termcodes
|
If you need to input sequences like <C-o> use
|
||||||
to replace the termcodes and then pass the resulting string to
|
|nvim_replace_termcodes| to replace the termcodes and then
|
||||||
nvim_feedkeys. You'll also want to enable escape_csi.
|
pass the resulting string to nvim_feedkeys. You'll also want
|
||||||
|
to enable escape_csi.
|
||||||
|
|
||||||
Example: >
|
Example: >
|
||||||
:let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
|
:let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -27,11 +27,21 @@ local lsp = {
|
|||||||
|
|
||||||
-- TODO improve handling of scratch buffers with LSP attached.
|
-- 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(...)
|
local function err_message(...)
|
||||||
nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
|
nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
|
||||||
nvim_command("redraw")
|
nvim_command("redraw")
|
||||||
end
|
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)
|
local function resolve_bufnr(bufnr)
|
||||||
validate { bufnr = { bufnr, 'n', true } }
|
validate { bufnr = { bufnr, 'n', true } }
|
||||||
if bufnr == nil or bufnr == 0 then
|
if bufnr == nil or bufnr == 0 then
|
||||||
@ -40,6 +50,11 @@ local function resolve_bufnr(bufnr)
|
|||||||
return bufnr
|
return bufnr
|
||||||
end
|
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)
|
local function is_dir(filename)
|
||||||
validate{filename={filename,'s'}}
|
validate{filename={filename,'s'}}
|
||||||
local stat = uv.fs_stat(filename)
|
local stat = uv.fs_stat(filename)
|
||||||
@ -55,6 +70,10 @@ local valid_encodings = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
local client_index = 0
|
local client_index = 0
|
||||||
|
--@private
|
||||||
|
--- Returns a new, unused client id.
|
||||||
|
---
|
||||||
|
--@returns (number) client id
|
||||||
local function next_client_id()
|
local function next_client_id()
|
||||||
client_index = client_index + 1
|
client_index = client_index + 1
|
||||||
return client_index
|
return client_index
|
||||||
@ -64,6 +83,12 @@ local active_clients = {}
|
|||||||
local all_buffer_active_clients = {}
|
local all_buffer_active_clients = {}
|
||||||
local uninitialized_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)
|
local function for_each_buffer_client(bufnr, callback)
|
||||||
validate {
|
validate {
|
||||||
callback = { callback, 'f' };
|
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;
|
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)
|
local function validate_encoding(encoding)
|
||||||
validate {
|
validate {
|
||||||
encoding = { encoding, 's' };
|
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))
|
or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding))
|
||||||
end
|
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)
|
function lsp._cmd_parts(input)
|
||||||
vim.validate{cmd={
|
vim.validate{cmd={
|
||||||
input,
|
input,
|
||||||
@ -114,12 +151,27 @@ function lsp._cmd_parts(input)
|
|||||||
return cmd, cmd_args
|
return cmd, cmd_args
|
||||||
end
|
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)
|
local function optional_validator(fn)
|
||||||
return function(v)
|
return function(v)
|
||||||
return v == nil or fn(v)
|
return v == nil or fn(v)
|
||||||
end
|
end
|
||||||
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)
|
local function validate_client_config(config)
|
||||||
validate {
|
validate {
|
||||||
config = { config, 't' };
|
config = { config, 't' };
|
||||||
@ -148,6 +200,11 @@ local function validate_client_config(config)
|
|||||||
}
|
}
|
||||||
end
|
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 function buf_get_full_text(bufnr)
|
||||||
local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n')
|
local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n')
|
||||||
if nvim_buf_get_option(bufnr, 'eol') then
|
if nvim_buf_get_option(bufnr, 'eol') then
|
||||||
@ -156,6 +213,11 @@ local function buf_get_full_text(bufnr)
|
|||||||
return text
|
return text
|
||||||
end
|
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)
|
local function text_document_did_open_handler(bufnr, client)
|
||||||
if not client.resolved_capabilities.text_document_open_close then
|
if not client.resolved_capabilities.text_document_open_close then
|
||||||
return
|
return
|
||||||
@ -176,74 +238,88 @@ local function text_document_did_open_handler(bufnr, client)
|
|||||||
util.buf_versions[bufnr] = params.textDocument.version
|
util.buf_versions[bufnr] = params.textDocument.version
|
||||||
end
|
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:
|
--- - Methods:
|
||||||
---
|
---
|
||||||
--- - request(method, params, [callback])
|
--- - request(method, params, [callback], bufnr)
|
||||||
--- Send a request to the server. If callback is not specified, it will use
|
--- Sends a request to the server.
|
||||||
--- {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
|
--- This is a thin wrapper around {client.rpc.request} with some additional
|
||||||
--- checking.
|
--- checking.
|
||||||
--- Returns a boolean to indicate if the notification was successful. If it
|
--- If {callback} is not specified, it will use {client.callbacks} to try to
|
||||||
--- is false, then it will always be false (the client has shutdown).
|
--- find a callback. If one is not found there, then an error will occur.
|
||||||
--- If it was successful, then it will return the request id as the second
|
--- Returns: {status}, {[client_id]}. {status} is a boolean indicating if
|
||||||
--- result. You can use this with `notify("$/cancel", { id = request_id })`
|
--- the notification was successful. If it is `false`, then it will always
|
||||||
--- to cancel the request. This helper is made automatically with
|
--- be `false` (the client has shutdown).
|
||||||
--- |vim.lsp.buf_request()|
|
--- If {status} is `true`, the function returns {request_id} as the second
|
||||||
--- Returns: status, [client_id]
|
--- result. You can use this with `client.cancel_request(request_id)`
|
||||||
|
--- to cancel the request.
|
||||||
---
|
---
|
||||||
--- - notify(method, params)
|
--- - notify(method, params)
|
||||||
--- This is just {client.rpc.notify}()
|
--- Sends a notification to an LSP server.
|
||||||
--- Returns a boolean to indicate if the notification was successful. If it
|
--- Returns: a boolean to indicate if the notification was successful. If
|
||||||
--- is false, then it will always be false (the client has shutdown).
|
--- it is false, then it will always be false (the client has shutdown).
|
||||||
--- Returns: status
|
|
||||||
---
|
---
|
||||||
--- - cancel_request(id)
|
--- - cancel_request(id)
|
||||||
--- This is just {client.rpc.notify}("$/cancelRequest", { id = id })
|
--- Cancels a request with a given request id.
|
||||||
--- Returns the same as `notify()`.
|
--- Returns: same as `notify()`.
|
||||||
---
|
---
|
||||||
--- - stop([force])
|
--- - 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.
|
--- 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
|
--- If you request to stop a client which has previously been requested to
|
||||||
--- shutdown, it will automatically escalate and force shutdown.
|
--- shutdown, it will automatically escalate and force shutdown.
|
||||||
---
|
---
|
||||||
--- - is_stopped()
|
--- - 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
|
--- - 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
|
--- used. Otherwise it is just the client id. This is used for
|
||||||
--- logs and messages.
|
--- logs and messages.
|
||||||
---
|
---
|
||||||
--- - offset_encoding (string): The encoding used for communicating
|
--- - {rpc} (table): RPC client object, for low level interaction with the
|
||||||
--- with the server. You can modify this in the `on_init` method
|
--- 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.
|
--- 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|.
|
--- 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()|.
|
--- 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.
|
--- `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
|
--- capabilities that we have detected based on the initialize
|
||||||
--- response from the server in `server_capabilities`.
|
--- response from the server in `server_capabilities`.
|
||||||
function lsp.client()
|
function lsp.client()
|
||||||
error()
|
error()
|
||||||
end
|
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.
|
--- Starts and initializes a client with the given configuration.
|
||||||
---
|
---
|
||||||
--- Parameters `cmd` and `root_dir` are required.
|
--- 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
|
--@param root_dir: (required, string) Directory where the LSP server will base
|
||||||
--- its rootUri on initialization.
|
--- its rootUri on initialization.
|
||||||
---
|
---
|
||||||
@ -271,8 +347,8 @@ end
|
|||||||
---
|
---
|
||||||
--@param callbacks Map of language server method names to
|
--@param callbacks Map of language server method names to
|
||||||
--- `function(err, method, params, client_id)` handler. Invoked for:
|
--- `function(err, method, params, client_id)` handler. Invoked for:
|
||||||
--- - Notifications from the server, where `err` will always be `nil`.
|
--- - Notifications to the server, where `err` will always be `nil`.
|
||||||
--- - Requests initiated by the server. For these you can respond by returning
|
--- - Requests by the server. For these you can respond by returning
|
||||||
--- two values: `result, err` where err must be shaped like a RPC error,
|
--- 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
|
--- i.e. `{ code, message, data? }`. Use |vim.lsp.rpc_response_error()| to
|
||||||
--- help with this.
|
--- help with this.
|
||||||
@ -297,7 +373,7 @@ end
|
|||||||
--@param before_init Callback with parameters (initialize_params, config)
|
--@param before_init Callback with parameters (initialize_params, config)
|
||||||
--- invoked before the LSP "initialize" phase, where `params` contains the
|
--- invoked before the LSP "initialize" phase, where `params` contains the
|
||||||
--- parameters being sent to the server and `config` is the config that was
|
--- 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.
|
--- they are sent.
|
||||||
---
|
---
|
||||||
--@param on_init Callback (client, initialize_result) invoked after LSP
|
--@param on_init Callback (client, initialize_result) invoked after LSP
|
||||||
@ -335,10 +411,23 @@ function lsp.start_client(config)
|
|||||||
|
|
||||||
local handlers = {}
|
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)
|
local function resolve_callback(method)
|
||||||
return callbacks[method] or default_callbacks[method]
|
return callbacks[method] or default_callbacks[method]
|
||||||
end
|
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)
|
function handlers.notification(method, params)
|
||||||
local _ = log.debug() and log.debug('notification', method, params)
|
local _ = log.debug() and log.debug('notification', method, params)
|
||||||
local callback = resolve_callback(method)
|
local callback = resolve_callback(method)
|
||||||
@ -348,6 +437,12 @@ function lsp.start_client(config)
|
|||||||
end
|
end
|
||||||
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)
|
function handlers.server_request(method, params)
|
||||||
local _ = log.debug() and log.debug('server_request', method, params)
|
local _ = log.debug() and log.debug('server_request', method, params)
|
||||||
local callback = resolve_callback(method)
|
local callback = resolve_callback(method)
|
||||||
@ -359,6 +454,13 @@ function lsp.start_client(config)
|
|||||||
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
|
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
|
||||||
end
|
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)
|
function handlers.on_error(code, err)
|
||||||
local _ = log.error() and log.error(log_prefix, "on_error", { code = lsp.client_errors[code], err = 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))
|
err_message(log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err))
|
||||||
@ -371,6 +473,11 @@ function lsp.start_client(config)
|
|||||||
end
|
end
|
||||||
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)
|
function handlers.on_exit(code, signal)
|
||||||
active_clients[client_id] = nil
|
active_clients[client_id] = nil
|
||||||
uninitialized_clients[client_id] = nil
|
uninitialized_clients[client_id] = nil
|
||||||
@ -411,6 +518,7 @@ function lsp.start_client(config)
|
|||||||
-- initialize finishes.
|
-- initialize finishes.
|
||||||
uninitialized_clients[client_id] = client;
|
uninitialized_clients[client_id] = client;
|
||||||
|
|
||||||
|
--@private
|
||||||
local function initialize()
|
local function initialize()
|
||||||
local valid_traces = {
|
local valid_traces = {
|
||||||
off = 'off'; messages = 'messages'; verbose = 'verbose';
|
off = 'off'; messages = 'messages'; verbose = 'verbose';
|
||||||
@ -488,6 +596,12 @@ function lsp.start_client(config)
|
|||||||
end)
|
end)
|
||||||
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 function unsupported_method(method)
|
||||||
local msg = "server doesn't support "..method
|
local msg = "server doesn't support "..method
|
||||||
local _ = log.warn() and log.warn(msg)
|
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)
|
return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
|
||||||
end
|
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)
|
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
|
if not callback then
|
||||||
callback = resolve_callback(method)
|
callback = resolve_callback(method)
|
||||||
or error(string.format("not found: %q request callback for client %q.", method, client.name))
|
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)
|
||||||
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(...)
|
function client.notify(...)
|
||||||
return rpc.notify(...)
|
return rpc.notify(...)
|
||||||
end
|
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)
|
function client.cancel_request(id)
|
||||||
validate{id = {id, 'n'}}
|
validate{id = {id, 'n'}}
|
||||||
return rpc.notify("$/cancelRequest", { id = id })
|
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
|
-- Track this so that we can escalate automatically if we've alredy tried a
|
||||||
-- graceful shutdown
|
-- graceful shutdown
|
||||||
local tried_graceful_shutdown = false
|
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)
|
function client.stop(force)
|
||||||
local handle = rpc.handle
|
local handle = rpc.handle
|
||||||
if handle:is_closing() then
|
if handle:is_closing() then
|
||||||
@ -554,10 +711,18 @@ function lsp.start_client(config)
|
|||||||
end)
|
end)
|
||||||
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()
|
function client.is_stopped()
|
||||||
return rpc.handle:is_closing()
|
return rpc.handle:is_closing()
|
||||||
end
|
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)
|
function client._on_attach(bufnr)
|
||||||
text_document_did_open_handler(bufnr, client)
|
text_document_did_open_handler(bufnr, client)
|
||||||
if config.on_attach then
|
if config.on_attach then
|
||||||
@ -571,6 +736,12 @@ function lsp.start_client(config)
|
|||||||
return client_id
|
return client_id
|
||||||
end
|
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 function once(fn)
|
||||||
local value
|
local value
|
||||||
return function(...)
|
return function(...)
|
||||||
@ -579,6 +750,9 @@ local function once(fn)
|
|||||||
end
|
end
|
||||||
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
|
local text_document_did_change_handler
|
||||||
do
|
do
|
||||||
local encoding_index = { ["utf-8"] = 1; ["utf-16"] = 2; ["utf-32"] = 3; }
|
local encoding_index = { ["utf-8"] = 1; ["utf-16"] = 2; ["utf-32"] = 3; }
|
||||||
@ -735,7 +909,7 @@ end
|
|||||||
---
|
---
|
||||||
--@param client_id client id number
|
--@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)
|
function lsp.get_client_by_id(client_id)
|
||||||
return active_clients[client_id]
|
return active_clients[client_id]
|
||||||
end
|
end
|
||||||
@ -769,7 +943,7 @@ end
|
|||||||
|
|
||||||
--- Gets all active clients.
|
--- Gets all active clients.
|
||||||
---
|
---
|
||||||
--@return Table of |vim.lsp.client| objects
|
--@returns Table of |vim.lsp.client| objects
|
||||||
function lsp.get_active_clients()
|
function lsp.get_active_clients()
|
||||||
return vim.tbl_values(active_clients)
|
return vim.tbl_values(active_clients)
|
||||||
end
|
end
|
||||||
@ -904,7 +1078,7 @@ end
|
|||||||
--@param findstart 0 or 1, decides behavior
|
--@param findstart 0 or 1, decides behavior
|
||||||
--@param base If findstart=0, text to match against
|
--@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=0: column where the completion starts, or -2 or -3
|
||||||
--- - findstart=1: list of matches (actually just calls |complete()|)
|
--- - findstart=1: list of matches (actually just calls |complete()|)
|
||||||
function lsp.omnifunc(findstart, base)
|
function lsp.omnifunc(findstart, base)
|
||||||
@ -948,6 +1122,10 @@ function lsp.omnifunc(findstart, base)
|
|||||||
return -2
|
return -2
|
||||||
end
|
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)
|
function lsp.client_is_stopped(client_id)
|
||||||
return active_clients[client_id] == nil
|
return active_clients[client_id] == nil
|
||||||
end
|
end
|
||||||
@ -992,12 +1170,17 @@ function lsp.set_log_level(level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Gets the path of the logfile used by the LSP client.
|
--- Gets the path of the logfile used by the LSP client.
|
||||||
|
--@returns (String) Path to logfile.
|
||||||
function lsp.get_log_path()
|
function lsp.get_log_path()
|
||||||
return log.get_filename()
|
return log.get_filename()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Define the LspDiagnostics signs if they're not defined already.
|
-- Defines the LspDiagnostics signs if they're not defined already.
|
||||||
do
|
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)
|
local function define_default_sign(name, properties)
|
||||||
if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
|
if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
|
||||||
vim.fn.sign_define(name, properties)
|
vim.fn.sign_define(name, properties)
|
||||||
|
@ -7,14 +7,41 @@ local list_extend = vim.list_extend
|
|||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
--@private
|
||||||
|
--- Returns nil if {status} is false or nil, otherwise returns the rest of the
|
||||||
|
--- arguments.
|
||||||
local function ok_or_nil(status, ...)
|
local function ok_or_nil(status, ...)
|
||||||
if not status then return end
|
if not status then return end
|
||||||
return ...
|
return ...
|
||||||
end
|
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, ...)
|
local function npcall(fn, ...)
|
||||||
return ok_or_nil(pcall(fn, ...))
|
return ok_or_nil(pcall(fn, ...))
|
||||||
end
|
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)
|
local function request(method, params, callback)
|
||||||
validate {
|
validate {
|
||||||
method = {method, 's'};
|
method = {method, 's'};
|
||||||
@ -23,9 +50,10 @@ local function request(method, params, callback)
|
|||||||
return vim.lsp.buf_request(0, method, params, callback)
|
return vim.lsp.buf_request(0, method, params, callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Sends a notification through all clients associated with current buffer.
|
--- Checks whether the language servers attached to the current buffer are
|
||||||
--
|
--- ready.
|
||||||
--@return `true` if server responds.
|
---
|
||||||
|
--@returns `true` if server responds.
|
||||||
function M.server_ready()
|
function M.server_ready()
|
||||||
return not not vim.lsp.buf_notify(0, "window/progress", {})
|
return not not vim.lsp.buf_notify(0, "window/progress", {})
|
||||||
end
|
end
|
||||||
@ -74,6 +102,12 @@ end
|
|||||||
|
|
||||||
--- Retrieves the completion items at the current cursor position. Can only be
|
--- Retrieves the completion items at the current cursor position. Can only be
|
||||||
--- called in Insert mode.
|
--- 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)
|
function M.completion(context)
|
||||||
local params = util.make_position_params()
|
local params = util.make_position_params()
|
||||||
params.context = context
|
params.context = context
|
||||||
@ -82,20 +116,27 @@ end
|
|||||||
|
|
||||||
--- Formats the current buffer.
|
--- Formats the current buffer.
|
||||||
---
|
---
|
||||||
--- The optional {options} table can be used to specify FormattingOptions, a
|
--@param options (optional, table) Can be used to specify FormattingOptions.
|
||||||
--- 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
|
--- Some unspecified options will be automatically derived from the current
|
||||||
--- Neovim options.
|
--- Neovim options.
|
||||||
|
--
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
|
||||||
function M.formatting(options)
|
function M.formatting(options)
|
||||||
local params = util.make_formatting_params(options)
|
local params = util.make_formatting_params(options)
|
||||||
return request('textDocument/formatting', params)
|
return request('textDocument/formatting', params)
|
||||||
end
|
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
|
--- 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)
|
function M.formatting_sync(options, timeout_ms)
|
||||||
local params = util.make_formatting_params(options)
|
local params = util.make_formatting_params(options)
|
||||||
local result = vim.lsp.buf_request_sync(0, "textDocument/formatting", params, timeout_ms)
|
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)
|
vim.lsp.util.apply_text_edits(result)
|
||||||
end
|
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)
|
function M.range_formatting(options, start_pos, end_pos)
|
||||||
validate {
|
validate {
|
||||||
options = {options, 't', true};
|
options = {options, 't', true};
|
||||||
@ -138,8 +186,10 @@ function M.range_formatting(options, start_pos, end_pos)
|
|||||||
return request('textDocument/rangeFormatting', params)
|
return request('textDocument/rangeFormatting', params)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Renames all references to the symbol under the cursor. If {new_name} is not
|
--- Renames all references to the symbol under the cursor.
|
||||||
--- provided, the user will be prompted for a new name using |input()|.
|
---
|
||||||
|
--@param new_name (string) If not provided, the user will be prompted for a new
|
||||||
|
---name using |input()|.
|
||||||
function M.rename(new_name)
|
function M.rename(new_name)
|
||||||
-- TODO(ashkan) use prepareRename
|
-- 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.
|
-- * 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.
|
--- 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)
|
function M.references(context)
|
||||||
validate { context = { context, 't', true } }
|
validate { context = { context, 't', true } }
|
||||||
local params = util.make_position_params()
|
local params = util.make_position_params()
|
||||||
@ -169,6 +221,7 @@ function M.document_symbol()
|
|||||||
request('textDocument/documentSymbol', params)
|
request('textDocument/documentSymbol', params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@private
|
||||||
local function pick_call_hierarchy_item(call_hierarchy_items)
|
local function pick_call_hierarchy_item(call_hierarchy_items)
|
||||||
if not call_hierarchy_items then return end
|
if not call_hierarchy_items then return end
|
||||||
if #call_hierarchy_items == 1 then
|
if #call_hierarchy_items == 1 then
|
||||||
@ -186,6 +239,9 @@ local function pick_call_hierarchy_item(call_hierarchy_items)
|
|||||||
return choice
|
return choice
|
||||||
end
|
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()
|
function M.incoming_calls()
|
||||||
local params = util.make_position_params()
|
local params = util.make_position_params()
|
||||||
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
|
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
|
||||||
@ -194,6 +250,9 @@ function M.incoming_calls()
|
|||||||
end)
|
end)
|
||||||
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()
|
function M.outgoing_calls()
|
||||||
local params = util.make_position_params()
|
local params = util.make_position_params()
|
||||||
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
|
request('textDocument/prepareCallHierarchy', params, function(_, _, result)
|
||||||
@ -204,9 +263,11 @@ end
|
|||||||
|
|
||||||
--- Lists all symbols in the current workspace in the quickfix window.
|
--- Lists all symbols in the current workspace in the quickfix window.
|
||||||
---
|
---
|
||||||
--- The list is filtered against the optional argument {query};
|
--- The list is filtered against {query}; if the argument is omitted from the
|
||||||
--- if the argument is omitted from the call, the user is prompted to enter a string on the command line.
|
--- call, the user is prompted to enter a string on the command line. An empty
|
||||||
--- An empty string means no filtering is done.
|
--- string means no filtering is done.
|
||||||
|
---
|
||||||
|
--@param query (string, optional)
|
||||||
function M.workspace_symbol(query)
|
function M.workspace_symbol(query)
|
||||||
query = query or npcall(vfn.input, "Query: ")
|
query = query or npcall(vfn.input, "Query: ")
|
||||||
local params = {query = query}
|
local params = {query = query}
|
||||||
@ -227,10 +288,17 @@ function M.document_highlight()
|
|||||||
request('textDocument/documentHighlight', params)
|
request('textDocument/documentHighlight', params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Removes document highlights from current buffer.
|
||||||
|
---
|
||||||
function M.clear_references()
|
function M.clear_references()
|
||||||
util.buf_clear_references()
|
util.buf_clear_references()
|
||||||
end
|
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)
|
function M.code_action(context)
|
||||||
validate { context = { context, 't', true } }
|
validate { context = { context, 't', true } }
|
||||||
context = context or { diagnostics = util.get_line_diagnostics() }
|
context = context or { diagnostics = util.get_line_diagnostics() }
|
||||||
@ -239,6 +307,10 @@ function M.code_action(context)
|
|||||||
request('textDocument/codeAction', params)
|
request('textDocument/codeAction', params)
|
||||||
end
|
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)
|
function M.execute_command(command)
|
||||||
validate {
|
validate {
|
||||||
command = { command.command, 's' },
|
command = { command.command, 's' },
|
||||||
|
@ -7,17 +7,22 @@ local buf = require 'vim.lsp.buf'
|
|||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
--@private
|
||||||
|
--- Writes to error buffer.
|
||||||
|
--@param ... (table of strings) Will be concatenated before being written
|
||||||
local function err_message(...)
|
local function err_message(...)
|
||||||
api.nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
|
api.nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
|
||||||
api.nvim_command("redraw")
|
api.nvim_command("redraw")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
|
||||||
M['workspace/executeCommand'] = function(err, _)
|
M['workspace/executeCommand'] = function(err, _)
|
||||||
if err then
|
if err then
|
||||||
error("Could not execute code action: "..err.message)
|
error("Could not execute code action: "..err.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
|
||||||
M['textDocument/codeAction'] = function(_, _, actions)
|
M['textDocument/codeAction'] = function(_, _, actions)
|
||||||
if actions == nil or vim.tbl_isempty(actions) then
|
if actions == nil or vim.tbl_isempty(actions) then
|
||||||
print("No code actions available")
|
print("No code actions available")
|
||||||
@ -51,6 +56,7 @@ M['textDocument/codeAction'] = function(_, _, actions)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
|
||||||
M['workspace/applyEdit'] = function(_, _, workspace_edit)
|
M['workspace/applyEdit'] = function(_, _, workspace_edit)
|
||||||
if not workspace_edit then return end
|
if not workspace_edit then return end
|
||||||
-- TODO(ashkan) Do something more with label?
|
-- TODO(ashkan) Do something more with label?
|
||||||
@ -64,6 +70,7 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_publishDiagnostics
|
||||||
M['textDocument/publishDiagnostics'] = function(_, _, result)
|
M['textDocument/publishDiagnostics'] = function(_, _, result)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
local uri = result.uri
|
local uri = result.uri
|
||||||
@ -102,6 +109,7 @@ M['textDocument/publishDiagnostics'] = function(_, _, result)
|
|||||||
vim.api.nvim_command("doautocmd User LspDiagnosticsChanged")
|
vim.api.nvim_command("doautocmd User LspDiagnosticsChanged")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
|
||||||
M['textDocument/references'] = function(_, _, result)
|
M['textDocument/references'] = function(_, _, result)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
util.set_qflist(util.locations_to_items(result))
|
util.set_qflist(util.locations_to_items(result))
|
||||||
@ -109,6 +117,13 @@ M['textDocument/references'] = function(_, _, result)
|
|||||||
api.nvim_command("wincmd p")
|
api.nvim_command("wincmd p")
|
||||||
end
|
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)
|
local symbol_callback = function(_, _, result, _, bufnr)
|
||||||
if not result or vim.tbl_isempty(result) then return end
|
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("copen")
|
||||||
api.nvim_command("wincmd p")
|
api.nvim_command("wincmd p")
|
||||||
end
|
end
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
|
||||||
M['textDocument/documentSymbol'] = symbol_callback
|
M['textDocument/documentSymbol'] = symbol_callback
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
|
||||||
M['workspace/symbol'] = symbol_callback
|
M['workspace/symbol'] = symbol_callback
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
|
||||||
M['textDocument/rename'] = function(_, _, result)
|
M['textDocument/rename'] = function(_, _, result)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
util.apply_workspace_edit(result)
|
util.apply_workspace_edit(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
|
||||||
M['textDocument/rangeFormatting'] = function(_, _, result)
|
M['textDocument/rangeFormatting'] = function(_, _, result)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
util.apply_text_edits(result)
|
util.apply_text_edits(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
|
||||||
M['textDocument/formatting'] = function(_, _, result)
|
M['textDocument/formatting'] = function(_, _, result)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
util.apply_text_edits(result)
|
util.apply_text_edits(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
||||||
M['textDocument/completion'] = function(_, _, result)
|
M['textDocument/completion'] = function(_, _, result)
|
||||||
if vim.tbl_isempty(result or {}) then return end
|
if vim.tbl_isempty(result or {}) then return end
|
||||||
local row, col = unpack(api.nvim_win_get_cursor(0))
|
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)
|
vim.fn.complete(textMatch+1, matches)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
|
||||||
M['textDocument/hover'] = function(_, method, result)
|
M['textDocument/hover'] = function(_, method, result)
|
||||||
util.focusable_float(method, function()
|
util.focusable_float(method, function()
|
||||||
if not (result and result.contents) then
|
if not (result and result.contents) then
|
||||||
@ -166,6 +188,12 @@ M['textDocument/hover'] = function(_, method, result)
|
|||||||
end)
|
end)
|
||||||
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)
|
local function location_callback(_, method, result)
|
||||||
if result == nil or vim.tbl_isempty(result) then
|
if result == nil or vim.tbl_isempty(result) then
|
||||||
local _ = log.info() and log.info(method, 'No location found')
|
local _ = log.info() and log.info(method, 'No location found')
|
||||||
@ -188,11 +216,16 @@ local function location_callback(_, method, result)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration
|
||||||
M['textDocument/declaration'] = location_callback
|
M['textDocument/declaration'] = location_callback
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
|
||||||
M['textDocument/definition'] = location_callback
|
M['textDocument/definition'] = location_callback
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition
|
||||||
M['textDocument/typeDefinition'] = location_callback
|
M['textDocument/typeDefinition'] = location_callback
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation
|
||||||
M['textDocument/implementation'] = location_callback
|
M['textDocument/implementation'] = location_callback
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
|
||||||
M['textDocument/signatureHelp'] = function(_, method, result)
|
M['textDocument/signatureHelp'] = function(_, method, result)
|
||||||
util.focusable_preview(method, function()
|
util.focusable_preview(method, function()
|
||||||
if not (result and result.signatures and result.signatures[1]) then
|
if not (result and result.signatures and result.signatures[1]) then
|
||||||
@ -208,15 +241,21 @@ M['textDocument/signatureHelp'] = function(_, method, result)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
|
||||||
M['textDocument/documentHighlight'] = function(_, _, result, _)
|
M['textDocument/documentHighlight'] = function(_, _, result, _)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
local bufnr = api.nvim_get_current_buf()
|
local bufnr = api.nvim_get_current_buf()
|
||||||
util.buf_highlight_references(bufnr, result)
|
util.buf_highlight_references(bufnr, result)
|
||||||
end
|
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)
|
local make_call_hierarchy_callback = function(direction)
|
||||||
-- result is a CallHierarchy{Incoming,Outgoing}Call[]
|
|
||||||
return function(_, _, result)
|
return function(_, _, result)
|
||||||
if not result then return end
|
if not result then return end
|
||||||
local items = {}
|
local items = {}
|
||||||
@ -237,10 +276,13 @@ local make_call_hierarchy_callback = function(direction)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/incomingCalls
|
||||||
M['callHierarchy/incomingCalls'] = make_call_hierarchy_callback('from')
|
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')
|
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)
|
M['window/logMessage'] = function(_, _, result, client_id)
|
||||||
local message_type = result.type
|
local message_type = result.type
|
||||||
local message = result.message
|
local message = result.message
|
||||||
@ -261,6 +303,7 @@ M['window/logMessage'] = function(_, _, result, client_id)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/showMessage
|
||||||
M['window/showMessage'] = function(_, _, result, client_id)
|
M['window/showMessage'] = function(_, _, result, client_id)
|
||||||
local message_type = result.type
|
local message_type = result.type
|
||||||
local message = result.message
|
local message = result.message
|
||||||
|
@ -21,12 +21,14 @@ local log_date_format = "%FT%H:%M:%S%z"
|
|||||||
|
|
||||||
do
|
do
|
||||||
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
|
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
|
||||||
|
--@private
|
||||||
local function path_join(...)
|
local function path_join(...)
|
||||||
return table.concat(vim.tbl_flatten{...}, path_sep)
|
return table.concat(vim.tbl_flatten{...}, path_sep)
|
||||||
end
|
end
|
||||||
local logfilename = path_join(vim.fn.stdpath('data'), 'lsp.log')
|
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()
|
function log.get_filename()
|
||||||
return logfilename
|
return logfilename
|
||||||
end
|
end
|
||||||
@ -74,6 +76,8 @@ end
|
|||||||
-- interfere with iterating the levels
|
-- interfere with iterating the levels
|
||||||
vim.tbl_add_reverse_lookup(log.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)
|
function log.set_level(level)
|
||||||
if type(level) == 'string' then
|
if type(level) == 'string' then
|
||||||
current_log_level = assert(log.levels[level:upper()], string.format("Invalid log level: %q", level))
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Return whether the level is sufficient for logging.
|
--- Checks whether the level is sufficient for logging.
|
||||||
--@param level number log level
|
--@param level number log level
|
||||||
|
--@returns (bool) true if would log, false if not
|
||||||
function log.should_log(level)
|
function log.should_log(level)
|
||||||
return level >= current_log_level
|
return level >= current_log_level
|
||||||
end
|
end
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
local protocol = {}
|
local protocol = {}
|
||||||
|
|
||||||
|
--@private
|
||||||
|
--- Returns {a} if it is not nil, otherwise returns {b}.
|
||||||
|
---
|
||||||
|
--@param a
|
||||||
|
--@param b
|
||||||
local function ifnil(a, b)
|
local function ifnil(a, b)
|
||||||
if a == nil then return b end
|
if a == nil then return b end
|
||||||
return a
|
return a
|
||||||
@ -9,12 +14,14 @@ end
|
|||||||
|
|
||||||
|
|
||||||
--[=[
|
--[=[
|
||||||
-- Useful for interfacing with:
|
--@private
|
||||||
-- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
|
--- Useful for interfacing with:
|
||||||
|
--- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
|
||||||
function transform_schema_comments()
|
function transform_schema_comments()
|
||||||
nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]]
|
nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]]
|
||||||
nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]]
|
nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]]
|
||||||
end
|
end
|
||||||
|
--@private
|
||||||
function transform_schema_to_table()
|
function transform_schema_to_table()
|
||||||
transform_schema_comments()
|
transform_schema_comments()
|
||||||
nvim.command [[silent! '<,'>s/: \S\+//]]
|
nvim.command [[silent! '<,'>s/: \S\+//]]
|
||||||
|
@ -5,6 +5,11 @@ local protocol = require('vim.lsp.protocol')
|
|||||||
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
|
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
|
||||||
|
|
||||||
-- TODO replace with a better implementation.
|
-- 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 function json_encode(data)
|
||||||
local status, result = pcall(vim.fn.json_encode, data)
|
local status, result = pcall(vim.fn.json_encode, data)
|
||||||
if status then
|
if status then
|
||||||
@ -13,6 +18,11 @@ local function json_encode(data)
|
|||||||
return nil, result
|
return nil, result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--@private
|
||||||
|
--- Decodes from JSON.
|
||||||
|
---
|
||||||
|
--@param data (string) Data to decode
|
||||||
|
--@returns (table) Decoded JSON object
|
||||||
local function json_decode(data)
|
local function json_decode(data)
|
||||||
local status, result = pcall(vim.fn.json_decode, data)
|
local status, result = pcall(vim.fn.json_decode, data)
|
||||||
if status then
|
if status then
|
||||||
@ -22,17 +32,26 @@ local function json_decode(data)
|
|||||||
end
|
end
|
||||||
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 function is_dir(filename)
|
||||||
local stat = vim.loop.fs_stat(filename)
|
local stat = vim.loop.fs_stat(filename)
|
||||||
return stat and stat.type == 'directory' or false
|
return stat and stat.type == 'directory' or false
|
||||||
end
|
end
|
||||||
|
|
||||||
local NIL = vim.NIL
|
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)
|
local function convert_NIL(v)
|
||||||
if v == NIL then return nil end
|
if v == NIL then return nil end
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@private
|
||||||
--- Merges current process env with the given env and returns the result as
|
--- Merges current process env with the given env and returns the result as
|
||||||
--- a list of "k=v" strings.
|
--- a list of "k=v" strings.
|
||||||
---
|
---
|
||||||
@ -42,6 +61,8 @@ end
|
|||||||
--- in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", }
|
--- 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", }
|
--- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", }
|
||||||
--- </pre>
|
--- </pre>
|
||||||
|
--@param env (table) table of environment variable assignments
|
||||||
|
--@returns (table) list of `"k=v"` strings
|
||||||
local function env_merge(env)
|
local function env_merge(env)
|
||||||
if env == nil then
|
if env == nil then
|
||||||
return env
|
return env
|
||||||
@ -56,6 +77,11 @@ local function env_merge(env)
|
|||||||
return final_env
|
return final_env
|
||||||
end
|
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)
|
local function format_message_with_content_length(encoded_message)
|
||||||
return table.concat {
|
return table.concat {
|
||||||
'Content-Length: '; tostring(#encoded_message); '\r\n\r\n';
|
'Content-Length: '; tostring(#encoded_message); '\r\n\r\n';
|
||||||
@ -63,8 +89,11 @@ local function format_message_with_content_length(encoded_message)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Parse an LSP Message's header
|
--@private
|
||||||
|
--- Parses an LSP Message's header
|
||||||
|
---
|
||||||
--@param header: The header to parse.
|
--@param header: The header to parse.
|
||||||
|
--@returns Parsed headers
|
||||||
local function parse_headers(header)
|
local function parse_headers(header)
|
||||||
if type(header) ~= 'string' then
|
if type(header) ~= 'string' then
|
||||||
return nil
|
return nil
|
||||||
@ -92,6 +121,8 @@ end
|
|||||||
-- case insensitive pattern.
|
-- case insensitive pattern.
|
||||||
local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end)
|
local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end)
|
||||||
|
|
||||||
|
--@private
|
||||||
|
--- The actual workhorse.
|
||||||
local function request_parser_loop()
|
local function request_parser_loop()
|
||||||
local buffer = ''
|
local buffer = ''
|
||||||
while true do
|
while true do
|
||||||
@ -138,6 +169,10 @@ local client_errors = vim.tbl_add_reverse_lookup {
|
|||||||
SERVER_RESULT_CALLBACK_ERROR = 7;
|
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)
|
local function format_rpc_error(err)
|
||||||
validate {
|
validate {
|
||||||
err = { err, 't' };
|
err = { err, 't' };
|
||||||
@ -182,23 +217,69 @@ local function rpc_response_error(code, message, data)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local default_handlers = {}
|
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)
|
function default_handlers.notification(method, params)
|
||||||
local _ = log.debug() and log.debug('notification', method, params)
|
local _ = log.debug() and log.debug('notification', method, params)
|
||||||
end
|
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)
|
function default_handlers.server_request(method, params)
|
||||||
local _ = log.debug() and log.debug('server_request', method, params)
|
local _ = log.debug() and log.debug('server_request', method, params)
|
||||||
return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound)
|
return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound)
|
||||||
end
|
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)
|
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
|
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)
|
function default_handlers.on_error(code, err)
|
||||||
local _ = log.error() and log.error('client_error:', client_errors[code], err)
|
local _ = log.error() and log.error('client_error:', client_errors[code], err)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create and start an RPC client.
|
--- Starts an LSP server process and create an LSP RPC client object to
|
||||||
-- @param cmd [
|
--- interact with it.
|
||||||
local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_params)
|
---
|
||||||
|
--@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})
|
local _ = log.info() and log.info("Starting RPC client", {cmd = cmd, args = cmd_args, extra = extra_spawn_params})
|
||||||
validate {
|
validate {
|
||||||
cmd = { cmd, 's' };
|
cmd = { cmd, 's' };
|
||||||
@ -242,6 +323,11 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
|
|||||||
|
|
||||||
local handle, pid
|
local handle, pid
|
||||||
do
|
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)
|
local function onexit(code, signal)
|
||||||
stdin:close()
|
stdin:close()
|
||||||
stdout: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)
|
handle, pid = uv.spawn(cmd, spawn_params, onexit)
|
||||||
end
|
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 function encode_and_send(payload)
|
||||||
local _ = log.debug() and log.debug("rpc.send.payload", payload)
|
local _ = log.debug() and log.debug("rpc.send.payload", payload)
|
||||||
if handle:is_closing() then return false end
|
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
|
return true
|
||||||
end
|
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)
|
local _ = log.debug() and log.debug("rpc.notify", method, params)
|
||||||
return encode_and_send {
|
return encode_and_send {
|
||||||
jsonrpc = "2.0";
|
jsonrpc = "2.0";
|
||||||
@ -285,6 +382,8 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@private
|
||||||
|
--- sends an error object to the remote LSP process.
|
||||||
local function send_response(request_id, err, result)
|
local function send_response(request_id, err, result)
|
||||||
return encode_and_send {
|
return encode_and_send {
|
||||||
id = request_id;
|
id = request_id;
|
||||||
@ -294,7 +393,14 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
|
|||||||
}
|
}
|
||||||
end
|
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 {
|
validate {
|
||||||
callback = { callback, 'f' };
|
callback = { callback, 'f' };
|
||||||
}
|
}
|
||||||
@ -320,11 +426,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
--@private
|
||||||
local function on_error(errkind, ...)
|
local function on_error(errkind, ...)
|
||||||
assert(client_errors[errkind])
|
assert(client_errors[errkind])
|
||||||
-- TODO what to do if this fails?
|
-- TODO what to do if this fails?
|
||||||
pcall(handlers.on_error, errkind, ...)
|
pcall(handlers.on_error, errkind, ...)
|
||||||
end
|
end
|
||||||
|
--@private
|
||||||
local function pcall_handler(errkind, status, head, ...)
|
local function pcall_handler(errkind, status, head, ...)
|
||||||
if not status then
|
if not status then
|
||||||
on_error(errkind, head, ...)
|
on_error(errkind, head, ...)
|
||||||
@ -332,6 +440,7 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
|
|||||||
end
|
end
|
||||||
return status, head, ...
|
return status, head, ...
|
||||||
end
|
end
|
||||||
|
--@private
|
||||||
local function try_call(errkind, fn, ...)
|
local function try_call(errkind, fn, ...)
|
||||||
return pcall_handler(errkind, pcall(fn, ...))
|
return pcall_handler(errkind, pcall(fn, ...))
|
||||||
end
|
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
|
-- time and log them. This would require storing the timestamp. I could call
|
||||||
-- them with an error then, perhaps.
|
-- them with an error then, perhaps.
|
||||||
|
|
||||||
|
--@private
|
||||||
local function handle_body(body)
|
local function handle_body(body)
|
||||||
local decoded, err = json_decode(body)
|
local decoded, err = json_decode(body)
|
||||||
if not decoded then
|
if not decoded then
|
||||||
@ -458,13 +568,13 @@ local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_para
|
|||||||
return {
|
return {
|
||||||
pid = pid;
|
pid = pid;
|
||||||
handle = handle;
|
handle = handle;
|
||||||
request = send_request;
|
request = request;
|
||||||
notify = send_notification;
|
notify = notify
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start = create_and_start_client;
|
start = start;
|
||||||
rpc_response_error = rpc_response_error;
|
rpc_response_error = rpc_response_error;
|
||||||
format_rpc_error = format_rpc_error;
|
format_rpc_error = format_rpc_error;
|
||||||
client_errors = client_errors;
|
client_errors = client_errors;
|
||||||
|
@ -7,6 +7,7 @@ local highlight = require 'vim.highlight'
|
|||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
-- FIXME: Expose in documentation
|
||||||
--- Diagnostics received from the server via `textDocument/publishDiagnostics`
|
--- Diagnostics received from the server via `textDocument/publishDiagnostics`
|
||||||
-- by buffer.
|
-- by buffer.
|
||||||
--
|
--
|
||||||
@ -33,18 +34,30 @@ local M = {}
|
|||||||
M.diagnostics_by_buf = {}
|
M.diagnostics_by_buf = {}
|
||||||
|
|
||||||
local split = vim.split
|
local split = vim.split
|
||||||
|
--@private
|
||||||
local function split_lines(value)
|
local function split_lines(value)
|
||||||
return split(value, '\n', true)
|
return split(value, '\n', true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@private
|
||||||
local function ok_or_nil(status, ...)
|
local function ok_or_nil(status, ...)
|
||||||
if not status then return end
|
if not status then return end
|
||||||
return ...
|
return ...
|
||||||
end
|
end
|
||||||
|
--@private
|
||||||
local function npcall(fn, ...)
|
local function npcall(fn, ...)
|
||||||
return ok_or_nil(pcall(fn, ...))
|
return ok_or_nil(pcall(fn, ...))
|
||||||
end
|
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)
|
function M.set_lines(lines, A, B, new_lines)
|
||||||
-- 0-indexing to 1-indexing
|
-- 0-indexing to 1-indexing
|
||||||
local i_0 = A[1] + 1
|
local i_0 = A[1] + 1
|
||||||
@ -78,6 +91,7 @@ function M.set_lines(lines, A, B, new_lines)
|
|||||||
return lines
|
return lines
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@private
|
||||||
local function sort_by_key(fn)
|
local function sort_by_key(fn)
|
||||||
return function(a,b)
|
return function(a,b)
|
||||||
local ka, kb = fn(a), fn(b)
|
local ka, kb = fn(a), fn(b)
|
||||||
@ -91,13 +105,15 @@ local function sort_by_key(fn)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--@private
|
||||||
local edit_sort_key = sort_by_key(function(e)
|
local edit_sort_key = sort_by_key(function(e)
|
||||||
return {e.A[1], e.A[2], e.i}
|
return {e.A[1], e.A[2], e.i}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
--@private
|
||||||
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
|
--- 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
|
--- Returns a zero-indexed column, since set_lines() does the conversion to
|
||||||
-- 1-indexed
|
--- 1-indexed
|
||||||
local function get_line_byte_from_position(bufnr, position)
|
local function get_line_byte_from_position(bufnr, position)
|
||||||
-- LSP's line and characters are 0-indexed
|
-- LSP's line and characters are 0-indexed
|
||||||
-- Vim's line and columns are 1-indexed
|
-- Vim's line and columns are 1-indexed
|
||||||
@ -114,6 +130,9 @@ local function get_line_byte_from_position(bufnr, position)
|
|||||||
return col
|
return col
|
||||||
end
|
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)
|
function M.apply_text_edits(text_edits, bufnr)
|
||||||
if not next(text_edits) then return end
|
if not next(text_edits) then return end
|
||||||
if not api.nvim_buf_is_loaded(bufnr) then
|
if not api.nvim_buf_is_loaded(bufnr) then
|
||||||
@ -168,20 +187,30 @@ end
|
|||||||
-- function M.glob_to_regex(glob)
|
-- function M.glob_to_regex(glob)
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
-- textDocument/completion response returns one of CompletionItem[], CompletionList or null.
|
--- Can be used to extract the completion items from a
|
||||||
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
|
--- `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)
|
function M.extract_completion_items(result)
|
||||||
if type(result) == 'table' and result.items then
|
if type(result) == 'table' and result.items then
|
||||||
|
-- result is a `CompletionList`
|
||||||
return result.items
|
return result.items
|
||||||
elseif result ~= nil then
|
elseif result ~= nil then
|
||||||
|
-- result is `CompletionItem[]`
|
||||||
return result
|
return result
|
||||||
else
|
else
|
||||||
|
-- result is `null`
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Apply the TextDocumentEdit response.
|
--- Applies a `TextDocumentEdit`, which is a list of changes to a single
|
||||||
-- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification
|
-- 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)
|
function M.apply_text_document_edit(text_document_edit)
|
||||||
local text_document = text_document_edit.textDocument
|
local text_document = text_document_edit.textDocument
|
||||||
local bufnr = vim.uri_to_bufnr(text_document.uri)
|
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)
|
M.apply_text_edits(text_document_edit.edits, bufnr)
|
||||||
end
|
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 function parse_snippet_rec(input, inner)
|
||||||
local res = ""
|
local res = ""
|
||||||
|
|
||||||
@ -248,15 +284,20 @@ local function parse_snippet_rec(input, inner)
|
|||||||
return res, input
|
return res, input
|
||||||
end
|
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)
|
function M.parse_snippet(input)
|
||||||
local res, _ = parse_snippet_rec(input, false)
|
local res, _ = parse_snippet_rec(input, false)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Sort by CompletionItem.sortText
|
--@private
|
||||||
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
--- Sorts by CompletionItem.sortText.
|
||||||
|
---
|
||||||
|
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
||||||
local function sort_completion_items(items)
|
local function sort_completion_items(items)
|
||||||
if items[1] and items[1].sortText then
|
if items[1] and items[1].sortText then
|
||||||
table.sort(items, function(a, b) return a.sortText < b.sortText
|
table.sort(items, function(a, b) return a.sortText < b.sortText
|
||||||
@ -264,9 +305,10 @@ local function sort_completion_items(items)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Returns text that should be inserted when selecting completion item. The precedence is as follows:
|
--@private
|
||||||
-- textEdit.newText > insertText > label
|
--- Returns text that should be inserted when selecting completion item. The
|
||||||
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
--- 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)
|
local function get_completion_word(item)
|
||||||
if item.textEdit ~= nil and item.textEdit.newText ~= nil then
|
if item.textEdit ~= nil and item.textEdit.newText ~= nil then
|
||||||
if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
|
if protocol.InsertTextFormat[item.insertTextFormat] == "PlainText" then
|
||||||
@ -284,8 +326,10 @@ local function get_completion_word(item)
|
|||||||
return item.label
|
return item.label
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Some language servers return complementary candidates whose prefixes do not match are also returned.
|
--@private
|
||||||
-- So we exclude completion candidates whose prefix does not match.
|
--- 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)
|
local function remove_unmatch_completion_items(items, prefix)
|
||||||
return vim.tbl_filter(function(item)
|
return vim.tbl_filter(function(item)
|
||||||
local word = get_completion_word(item)
|
local word = get_completion_word(item)
|
||||||
@ -293,16 +337,26 @@ local function remove_unmatch_completion_items(items, prefix)
|
|||||||
end, items)
|
end, items)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Acording to LSP spec, if the client set "completionItemKind.valueSet",
|
--- 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.
|
--- the client must handle it properly even if it receives a value outside the
|
||||||
-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
|
--- 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)
|
function M._get_completion_item_kind_name(completion_item_kind)
|
||||||
return protocol.CompletionItemKind[completion_item_kind] or "Unknown"
|
return protocol.CompletionItemKind[completion_item_kind] or "Unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Getting vim complete-items with incomplete flag.
|
--- Turns the result of a `textDocument/completion` request into vim-compatible
|
||||||
-- @params CompletionItem[], CompletionList or nil (https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
--- |complete-items|.
|
||||||
-- @return { matches = complete-items table, incomplete = boolean }
|
---
|
||||||
|
--@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)
|
function M.text_document_completion_list_to_complete_items(result, prefix)
|
||||||
local items = M.extract_completion_items(result)
|
local items = M.extract_completion_items(result)
|
||||||
if vim.tbl_isempty(items) then
|
if vim.tbl_isempty(items) then
|
||||||
@ -350,7 +404,10 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
|
|||||||
return matches
|
return matches
|
||||||
end
|
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)
|
function M.apply_workspace_edit(workspace_edit)
|
||||||
if workspace_edit.documentChanges then
|
if workspace_edit.documentChanges then
|
||||||
for _, change in ipairs(workspace_edit.documentChanges) do
|
for _, change in ipairs(workspace_edit.documentChanges) do
|
||||||
@ -375,9 +432,15 @@ function M.apply_workspace_edit(workspace_edit)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert any of MarkedString | MarkedString[] | MarkupContent into markdown text lines
|
--- Converts any of `MarkedString` | `MarkedString[]` | `MarkupContent` into
|
||||||
-- see https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_hover
|
--- a list of lines containing valid markdown. Useful to populate the hover
|
||||||
-- Useful for textDocument/hover, textDocument/signatureHelp, and potentially others.
|
--- 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)
|
function M.convert_input_to_markdown_lines(input, contents)
|
||||||
contents = contents or {}
|
contents = contents or {}
|
||||||
-- MarkedString variation 1
|
-- MarkedString variation 1
|
||||||
@ -416,8 +479,11 @@ function M.convert_input_to_markdown_lines(input, contents)
|
|||||||
return contents
|
return contents
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert SignatureHelp response to markdown lines.
|
--- Converts `textDocument/SignatureHelp` response to markdown lines.
|
||||||
-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
|
---
|
||||||
|
--@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)
|
function M.convert_signature_help_to_markdown_lines(signature_help)
|
||||||
if not signature_help.signatures then
|
if not signature_help.signatures then
|
||||||
return
|
return
|
||||||
@ -475,6 +541,13 @@ function M.convert_signature_help_to_markdown_lines(signature_help)
|
|||||||
return contents
|
return contents
|
||||||
end
|
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)
|
function M.make_floating_popup_options(width, height, opts)
|
||||||
validate {
|
validate {
|
||||||
opts = { opts, 't', true };
|
opts = { opts, 't', true };
|
||||||
@ -520,6 +593,10 @@ function M.make_floating_popup_options(width, height, opts)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Jumps to a location.
|
||||||
|
---
|
||||||
|
--@param location (`Location`|`LocationLink`)
|
||||||
|
--@returns `true` if the jump succeeded
|
||||||
function M.jump_to_location(location)
|
function M.jump_to_location(location)
|
||||||
-- location may be Location or LocationLink
|
-- location may be Location or LocationLink
|
||||||
local uri = location.uri or location.targetUri
|
local uri = location.uri or location.targetUri
|
||||||
@ -543,14 +620,14 @@ function M.jump_to_location(location)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Preview a location in a floating windows
|
--- Previews a location in a floating window
|
||||||
---
|
---
|
||||||
--- behavior depends on type of location:
|
--- behavior depends on type of location:
|
||||||
--- - for Location, range is shown (e.g., function definition)
|
--- - for Location, range is shown (e.g., function definition)
|
||||||
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
|
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
|
||||||
---
|
---
|
||||||
--@param location a single Location or LocationLink
|
--@param location a single `Location` or `LocationLink`
|
||||||
--@return bufnr,winnr buffer and window number of floating window or nil
|
--@returns (bufnr,winnr) buffer and window number of floating window or nil
|
||||||
function M.preview_location(location)
|
function M.preview_location(location)
|
||||||
-- location may be LocationLink or Location (more useful for the former)
|
-- location may be LocationLink or Location (more useful for the former)
|
||||||
local uri = location.targetUri or location.uri
|
local uri = location.targetUri or location.uri
|
||||||
@ -565,6 +642,7 @@ function M.preview_location(location)
|
|||||||
return M.open_floating_preview(contents, filetype)
|
return M.open_floating_preview(contents, filetype)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--@private
|
||||||
local function find_window_by_var(name, value)
|
local function find_window_by_var(name, value)
|
||||||
for _, win in ipairs(api.nvim_list_wins()) do
|
for _, win in ipairs(api.nvim_list_wins()) do
|
||||||
if npcall(api.nvim_win_get_var, win, name) == value then
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if a window with `unique_name` tagged is associated with the current
|
--- Enters/leaves the focusable window associated with the current buffer via the
|
||||||
-- buffer. If not, make a new preview.
|
--window - variable `unique_name`. If no such window exists, run the function
|
||||||
--
|
--{fn}.
|
||||||
-- fn()'s return bufnr, winnr
|
---
|
||||||
-- case that a new floating window should be created.
|
--@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)
|
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
|
if npcall(api.nvim_win_get_var, 0, unique_name) then
|
||||||
return api.nvim_command("wincmd p")
|
return api.nvim_command("wincmd p")
|
||||||
end
|
end
|
||||||
@ -598,18 +682,21 @@ function M.focusable_float(unique_name, fn)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if a window with `unique_name` tagged is associated with the current
|
--- Focuses/unfocuses the floating preview window associated with the current
|
||||||
-- buffer. If not, make a new preview.
|
--- buffer via the window variable `unique_name`. If no such preview window
|
||||||
--
|
--- exists, makes a new one.
|
||||||
-- fn()'s return values will be passed directly to open_floating_preview in the
|
---
|
||||||
-- case that a new floating window should be created.
|
--@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)
|
function M.focusable_preview(unique_name, fn)
|
||||||
return M.focusable_float(unique_name, function()
|
return M.focusable_float(unique_name, function()
|
||||||
return M.open_floating_preview(fn())
|
return M.open_floating_preview(fn())
|
||||||
end)
|
end)
|
||||||
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 contents table of lines to trim and pad
|
||||||
--@param opts dictionary with optional fields
|
--@param opts dictionary with optional fields
|
||||||
@ -617,7 +704,7 @@ end
|
|||||||
-- - pad_right number of columns to pad contents at right (default 1)
|
-- - 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_top number of lines to pad contents at top (default 0)
|
||||||
-- - pad_bottom number of lines to pad contents at bottom (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)
|
function M._trim_and_pad(contents, opts)
|
||||||
validate {
|
validate {
|
||||||
contents = { contents, 't' };
|
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.
|
--- blocks and converting them into highlighted code.
|
||||||
--- This will by default insert a blank line separator after those code block
|
--- This will by default insert a blank line separator after those code block
|
||||||
--- regions to improve readability.
|
--- regions to improve readability.
|
||||||
--- The result is shown in a floating preview
|
--- The result is shown in a floating preview.
|
||||||
--- TODO: refactor to separate stripping/converting and make use of open_floating_preview
|
|
||||||
---
|
---
|
||||||
--@param contents table of lines to show in window
|
--@param contents table of lines to show in window
|
||||||
--@param opts dictionary with optional fields
|
--@param opts dictionary with optional fields
|
||||||
@ -664,7 +752,7 @@ end
|
|||||||
-- - pad_top number of lines to pad contents at top
|
-- - pad_top number of lines to pad contents at top
|
||||||
-- - pad_bottom number of lines to pad contents at bottom
|
-- - pad_bottom number of lines to pad contents at bottom
|
||||||
-- - separator insert separator after code block
|
-- - 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)
|
function M.fancy_floating_markdown(contents, opts)
|
||||||
validate {
|
validate {
|
||||||
contents = { contents, 't' };
|
contents = { contents, 't' };
|
||||||
@ -738,6 +826,7 @@ function M.fancy_floating_markdown(contents, opts)
|
|||||||
|
|
||||||
vim.cmd("ownsyntax markdown")
|
vim.cmd("ownsyntax markdown")
|
||||||
local idx = 1
|
local idx = 1
|
||||||
|
--@private
|
||||||
local function apply_syntax_to_region(ft, start, finish)
|
local function apply_syntax_to_region(ft, start, finish)
|
||||||
if ft == '' then return end
|
if ft == '' then return end
|
||||||
local name = ft..idx
|
local name = ft..idx
|
||||||
@ -763,11 +852,17 @@ function M.fancy_floating_markdown(contents, opts)
|
|||||||
return bufnr, winnr
|
return bufnr, winnr
|
||||||
end
|
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)
|
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)")
|
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
|
||||||
end
|
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 contents table of lines to show in window
|
||||||
--@param opts dictionary with optional fields
|
--@param opts dictionary with optional fields
|
||||||
@ -776,7 +871,7 @@ end
|
|||||||
-- - wrap_at character to wrap at for computing height
|
-- - wrap_at character to wrap at for computing height
|
||||||
-- - max_width maximal width of floating window
|
-- - max_width maximal width of floating window
|
||||||
-- - max_height maximal height 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)
|
function M._make_floating_popup_size(contents, opts)
|
||||||
validate {
|
validate {
|
||||||
contents = { contents, 't' };
|
contents = { contents, 't' };
|
||||||
@ -827,7 +922,7 @@ function M._make_floating_popup_size(contents, opts)
|
|||||||
return width, height
|
return width, height
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Show contents in a floating window
|
--- Shows contents in a floating window.
|
||||||
---
|
---
|
||||||
--@param contents table of lines to show in window
|
--@param contents table of lines to show in window
|
||||||
--@param filetype string of filetype to set for opened buffer
|
--@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_right number of columns to pad contents at right
|
||||||
-- - pad_top number of lines to pad contents at top
|
-- - pad_top number of lines to pad contents at top
|
||||||
-- - pad_bottom number of lines to pad contents at bottom
|
-- - 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)
|
function M.open_floating_preview(contents, filetype, opts)
|
||||||
validate {
|
validate {
|
||||||
contents = { contents, 't' };
|
contents = { contents, 't' };
|
||||||
@ -912,6 +1008,9 @@ do
|
|||||||
severity_floating_highlights[severity] = floating_highlight_name
|
severity_floating_highlights[severity] = floating_highlight_name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Clears diagnostics for a buffer.
|
||||||
|
---
|
||||||
|
--@param bufnr (number) buffer id
|
||||||
function M.buf_clear_diagnostics(bufnr)
|
function M.buf_clear_diagnostics(bufnr)
|
||||||
validate { bufnr = {bufnr, 'n', true} }
|
validate { bufnr = {bufnr, 'n', true} }
|
||||||
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
|
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)
|
api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
|
||||||
end
|
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)
|
function M.get_severity_highlight_name(severity)
|
||||||
return severity_highlights[severity]
|
return severity_highlights[severity]
|
||||||
end
|
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()
|
function M.get_line_diagnostics()
|
||||||
local bufnr = api.nvim_get_current_buf()
|
local bufnr = api.nvim_get_current_buf()
|
||||||
local linenr = api.nvim_win_get_cursor(0)[1] - 1
|
local linenr = api.nvim_win_get_cursor(0)[1] - 1
|
||||||
@ -941,6 +1048,8 @@ do
|
|||||||
return diagnostics_by_line[linenr] or {}
|
return diagnostics_by_line[linenr] or {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Displays the diagnostics for the current line in a floating hover
|
||||||
|
--- window.
|
||||||
function M.show_line_diagnostics()
|
function M.show_line_diagnostics()
|
||||||
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
|
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
|
||||||
-- if #marks == 0 then
|
-- if #marks == 0 then
|
||||||
@ -977,10 +1086,10 @@ do
|
|||||||
return popup_bufnr, winnr
|
return popup_bufnr, winnr
|
||||||
end
|
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 bufnr (number) buffer id for which the diagnostics are for
|
||||||
--@param diagnostics Diagnostics[] received from the language server.
|
--@param diagnostics list of `Diagnostic`s received from the LSP server
|
||||||
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
|
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
|
||||||
validate {
|
validate {
|
||||||
bufnr = {bufnr, 'n', true};
|
bufnr = {bufnr, 'n', true};
|
||||||
@ -1000,6 +1109,10 @@ do
|
|||||||
M.diagnostics_by_buf[bufnr] = diagnostics
|
M.diagnostics_by_buf[bufnr] = diagnostics
|
||||||
end
|
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)
|
function M.buf_diagnostics_underline(bufnr, diagnostics)
|
||||||
for _, diagnostic in ipairs(diagnostics) do
|
for _, diagnostic in ipairs(diagnostics) do
|
||||||
local start = diagnostic.range["start"]
|
local start = diagnostic.range["start"]
|
||||||
@ -1020,11 +1133,18 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Removes document highlights from a buffer.
|
||||||
|
---
|
||||||
|
--@param bufnr buffer id
|
||||||
function M.buf_clear_references(bufnr)
|
function M.buf_clear_references(bufnr)
|
||||||
validate { bufnr = {bufnr, 'n', true} }
|
validate { bufnr = {bufnr, 'n', true} }
|
||||||
api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
|
api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
|
||||||
end
|
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)
|
function M.buf_highlight_references(bufnr, references)
|
||||||
validate { bufnr = {bufnr, 'n', true} }
|
validate { bufnr = {bufnr, 'n', true} }
|
||||||
for _, reference in ipairs(references) do
|
for _, reference in ipairs(references) do
|
||||||
@ -1040,11 +1160,19 @@ do
|
|||||||
end
|
end
|
||||||
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)
|
function M.diagnostics_group_by_line(diagnostics)
|
||||||
if not diagnostics then return end
|
if not diagnostics then return end
|
||||||
local diagnostics_by_line = {}
|
local diagnostics_by_line = {}
|
||||||
for _, diagnostic in ipairs(diagnostics) do
|
for _, diagnostic in ipairs(diagnostics) do
|
||||||
local start = diagnostic.range.start
|
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]
|
local line_diagnostics = diagnostics_by_line[start.line]
|
||||||
if not line_diagnostics then
|
if not line_diagnostics then
|
||||||
line_diagnostics = {}
|
line_diagnostics = {}
|
||||||
@ -1055,6 +1183,11 @@ do
|
|||||||
return diagnostics_by_line
|
return diagnostics_by_line
|
||||||
end
|
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)
|
function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
|
||||||
if not diagnostics then
|
if not diagnostics then
|
||||||
return
|
return
|
||||||
@ -1093,8 +1226,7 @@ do
|
|||||||
--- </pre>
|
--- </pre>
|
||||||
---
|
---
|
||||||
--@param kind Diagnostic severity kind: See |vim.lsp.protocol.DiagnosticSeverity|
|
--@param kind Diagnostic severity kind: See |vim.lsp.protocol.DiagnosticSeverity|
|
||||||
---
|
--@returns Count of diagnostics
|
||||||
--@return Count of diagnostics
|
|
||||||
function M.buf_diagnostics_count(kind)
|
function M.buf_diagnostics_count(kind)
|
||||||
local bufnr = vim.api.nvim_get_current_buf()
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
local diagnostics = M.diagnostics_by_buf[bufnr]
|
local diagnostics = M.diagnostics_by_buf[bufnr]
|
||||||
@ -1115,7 +1247,7 @@ do
|
|||||||
[protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
|
[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:
|
--- 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}
|
return {v.start.line, v.start.character}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Returns the items with the byte position calculated correctly and in sorted
|
--- Returns the items with the byte position calculated correctly and in sorted
|
||||||
-- order.
|
--- 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)
|
function M.locations_to_items(locations)
|
||||||
local items = {}
|
local items = {}
|
||||||
local grouped = setmetatable({}, {
|
local grouped = setmetatable({}, {
|
||||||
@ -1180,6 +1315,10 @@ function M.locations_to_items(locations)
|
|||||||
return items
|
return items
|
||||||
end
|
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)
|
function M.set_loclist(items)
|
||||||
vim.fn.setloclist(0, {}, ' ', {
|
vim.fn.setloclist(0, {}, ' ', {
|
||||||
title = 'Language Server';
|
title = 'Language Server';
|
||||||
@ -1187,6 +1326,10 @@ function M.set_loclist(items)
|
|||||||
})
|
})
|
||||||
end
|
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)
|
function M.set_qflist(items)
|
||||||
vim.fn.setqflist({}, ' ', {
|
vim.fn.setqflist({}, ' ', {
|
||||||
title = 'Language Server';
|
title = 'Language Server';
|
||||||
@ -1201,10 +1344,11 @@ function M._get_symbol_kind_name(symbol_kind)
|
|||||||
return protocol.SymbolKind[symbol_kind] or "Unknown"
|
return protocol.SymbolKind[symbol_kind] or "Unknown"
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Convert symbols to quickfix list items
|
--- Converts symbols to quickfix list items.
|
||||||
---
|
---
|
||||||
--@param symbols DocumentSymbol[] or SymbolInformation[]
|
--@param symbols DocumentSymbol[] or SymbolInformation[]
|
||||||
function M.symbols_to_items(symbols, bufnr)
|
function M.symbols_to_items(symbols, bufnr)
|
||||||
|
--@private
|
||||||
local function _symbols_to_items(_symbols, _items, _bufnr)
|
local function _symbols_to_items(_symbols, _items, _bufnr)
|
||||||
for _, symbol in ipairs(_symbols) do
|
for _, symbol in ipairs(_symbols) do
|
||||||
if symbol.location then -- SymbolInformation type
|
if symbol.location then -- SymbolInformation type
|
||||||
@ -1239,7 +1383,9 @@ function M.symbols_to_items(symbols, bufnr)
|
|||||||
return _symbols_to_items(symbols, {}, bufnr)
|
return _symbols_to_items(symbols, {}, bufnr)
|
||||||
end
|
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)
|
function M.trim_empty_lines(lines)
|
||||||
local start = 1
|
local start = 1
|
||||||
for i = 1, #lines do
|
for i = 1, #lines do
|
||||||
@ -1258,11 +1404,13 @@ function M.trim_empty_lines(lines)
|
|||||||
return vim.list_extend({}, lines, start, finish)
|
return vim.list_extend({}, lines, start, finish)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Accepts markdown lines and tries to reduce it to a filetype if it is
|
--- Accepts markdown lines and tries to reduce them to a filetype if they
|
||||||
-- just a single code block.
|
--- comprise just a single code block.
|
||||||
-- Note: This modifies the input.
|
---
|
||||||
--
|
--- CAUTION: Modifies the input in-place!
|
||||||
-- Returns: filetype or 'markdown' if it was unchanged.
|
---
|
||||||
|
--@param lines (table) list of lines
|
||||||
|
--@returns (string) filetype or 'markdown' if it was unchanged.
|
||||||
function M.try_trim_markdown_code_blocks(lines)
|
function M.try_trim_markdown_code_blocks(lines)
|
||||||
local language_id = lines[1]:match("^```(.*)")
|
local language_id = lines[1]:match("^```(.*)")
|
||||||
if language_id then
|
if language_id then
|
||||||
@ -1285,6 +1433,7 @@ function M.try_trim_markdown_code_blocks(lines)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local str_utfindex = vim.str_utfindex
|
local str_utfindex = vim.str_utfindex
|
||||||
|
--@private
|
||||||
local function make_position_param()
|
local function make_position_param()
|
||||||
local row, col = unpack(api.nvim_win_get_cursor(0))
|
local row, col = unpack(api.nvim_win_get_cursor(0))
|
||||||
row = row - 1
|
row = row - 1
|
||||||
@ -1293,6 +1442,10 @@ local function make_position_param()
|
|||||||
return { line = row; character = col; }
|
return { line = row; character = col; }
|
||||||
end
|
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()
|
function M.make_position_params()
|
||||||
return {
|
return {
|
||||||
textDocument = M.make_text_document_params();
|
textDocument = M.make_text_document_params();
|
||||||
@ -1300,6 +1453,13 @@ function M.make_position_params()
|
|||||||
}
|
}
|
||||||
end
|
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()
|
function M.make_range_params()
|
||||||
local position = make_position_param()
|
local position = make_position_param()
|
||||||
return {
|
return {
|
||||||
@ -1308,11 +1468,15 @@ function M.make_range_params()
|
|||||||
}
|
}
|
||||||
end
|
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()
|
function M.make_text_document_params()
|
||||||
return { uri = vim.uri_from_bufnr(0) }
|
return { uri = vim.uri_from_bufnr(0) }
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Get visual width of tabstop.
|
--- Returns visual width of tabstop.
|
||||||
---
|
---
|
||||||
--@see |softtabstop|
|
--@see |softtabstop|
|
||||||
--@param bufnr (optional, number): Buffer handle, defaults to current
|
--@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
|
return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop
|
||||||
end
|
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)
|
function M.make_formatting_params(options)
|
||||||
validate { options = {options, 't', true} }
|
validate { options = {options, 't', true} }
|
||||||
options = vim.tbl_extend('keep', options or {}, {
|
options = vim.tbl_extend('keep', options or {}, {
|
||||||
@ -1336,9 +1505,12 @@ function M.make_formatting_params(options)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- @param buf buffer handle or 0 for current.
|
--- 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 row 0-indexed line
|
||||||
--@param col 0-indexed byte offset in 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)
|
function M.character_offset(buf, row, col)
|
||||||
local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
|
local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
|
||||||
-- If the col is past the EOL, use the line length.
|
-- If the col is past the EOL, use the line length.
|
||||||
|
@ -960,7 +960,11 @@ def main(config):
|
|||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
for filename in CONFIG[target]['section_order']:
|
for filename in CONFIG[target]['section_order']:
|
||||||
|
try:
|
||||||
title, helptag, section_doc = sections.pop(filename)
|
title, helptag, section_doc = sections.pop(filename)
|
||||||
|
except KeyError:
|
||||||
|
print("Warning:", filename, "has empty docs, skipping")
|
||||||
|
continue
|
||||||
i += 1
|
i += 1
|
||||||
if filename not in CONFIG[target]['append_only']:
|
if filename not in CONFIG[target]['append_only']:
|
||||||
docs += sep
|
docs += sep
|
||||||
|
@ -203,10 +203,10 @@ Integer nvim_get_hl_id_by_name(String name)
|
|||||||
/// flags. This is a blocking call, unlike |nvim_input()|.
|
/// flags. This is a blocking call, unlike |nvim_input()|.
|
||||||
///
|
///
|
||||||
/// On execution error: does not fail, but updates v:errmsg.
|
/// On execution error: does not fail, but updates v:errmsg.
|
||||||
//
|
///
|
||||||
// If you need to input sequences like <C-o> use nvim_replace_termcodes
|
/// If you need to input sequences like <C-o> use |nvim_replace_termcodes|
|
||||||
// to replace the termcodes and then pass the resulting string to
|
/// to replace the termcodes and then pass the resulting string to
|
||||||
// nvim_feedkeys. You'll also want to enable escape_csi.
|
/// nvim_feedkeys. You'll also want to enable escape_csi.
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// <pre>
|
/// <pre>
|
||||||
|
Loading…
Reference in New Issue
Block a user