2019-11-24 04:01:18 -07:00
local vim = vim
2019-11-20 15:21:57 -07:00
local validate = vim.validate
2019-11-20 16:35:18 -07:00
local vfn = vim.fn
2019-11-20 15:21:57 -07:00
local util = require ' vim.lsp.util '
local M = { }
2020-08-19 09:17:08 -07:00
--@private
--- Returns nil if {status} is false or nil, otherwise returns the rest of the
--- arguments.
2019-11-20 15:21:57 -07:00
local function ok_or_nil ( status , ... )
2019-11-20 17:16:36 -07:00
if not status then return end
return ...
2019-11-20 15:21:57 -07:00
end
2020-08-19 09:17:08 -07:00
--@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
2019-11-20 15:21:57 -07:00
local function npcall ( fn , ... )
2019-11-20 17:16:36 -07:00
return ok_or_nil ( pcall ( fn , ... ) )
2019-11-20 15:21:57 -07:00
end
2020-08-19 09:17:08 -07:00
--@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()|
2019-11-20 16:35:18 -07:00
local function request ( method , params , callback )
2019-11-20 17:16:36 -07:00
validate {
method = { method , ' s ' } ;
2019-11-26 06:59:40 -07:00
callback = { callback , ' f ' , true } ;
2019-11-20 17:16:36 -07:00
}
2019-11-26 06:59:40 -07:00
return vim.lsp . buf_request ( 0 , method , params , callback )
2019-11-20 16:35:18 -07:00
end
2020-08-19 09:17:08 -07:00
--- Checks whether the language servers attached to the current buffer are
--- ready.
---
--@returns `true` if server responds.
2020-02-26 12:22:14 -07:00
function M . server_ready ( )
return not not vim.lsp . buf_notify ( 0 , " window/progress " , { } )
end
2020-07-19 14:16:12 -07:00
--- Displays hover information about the symbol under the cursor in a floating
--- window. Calling the function twice will jump into the floating window.
2019-11-20 16:35:18 -07:00
function M . hover ( )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-26 06:59:40 -07:00
request ( ' textDocument/hover ' , params )
2019-11-20 15:21:57 -07:00
end
2020-07-19 14:16:12 -07:00
--- Jumps to the declaration of the symbol under the cursor.
---
2019-11-20 15:21:57 -07:00
function M . declaration ( )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-26 06:59:40 -07:00
request ( ' textDocument/declaration ' , params )
2019-11-20 16:35:18 -07:00
end
2020-07-19 14:16:12 -07:00
--- Jumps to the definition of the symbol under the cursor.
---
2019-11-20 16:35:18 -07:00
function M . definition ( )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-26 06:59:40 -07:00
request ( ' textDocument/definition ' , params )
2019-11-20 15:21:57 -07:00
end
2020-07-19 14:16:12 -07:00
--- Jumps to the definition of the type of the symbol under the cursor.
---
2019-11-20 15:21:57 -07:00
function M . type_definition ( )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-26 06:59:40 -07:00
request ( ' textDocument/typeDefinition ' , params )
2019-11-20 15:21:57 -07:00
end
2020-07-19 14:16:12 -07:00
--- Lists all the implementations for the symbol under the cursor in the
--- quickfix window.
2019-11-20 15:21:57 -07:00
function M . implementation ( )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-26 06:59:40 -07:00
request ( ' textDocument/implementation ' , params )
2019-11-20 17:03:32 -07:00
end
2020-07-19 14:16:12 -07:00
--- Displays signature information about the symbol under the cursor in a
--- floating window.
2019-11-20 16:35:18 -07:00
function M . signature_help ( )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-26 06:59:40 -07:00
request ( ' textDocument/signatureHelp ' , params )
2019-11-20 15:21:57 -07:00
end
2020-07-19 14:16:12 -07:00
--- Retrieves the completion items at the current cursor position. Can only be
--- called in Insert mode.
2020-08-19 09:17:08 -07:00
---
--@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|
2019-11-20 16:35:18 -07:00
function M . completion ( context )
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2019-11-20 17:16:36 -07:00
params.context = context
2019-11-26 06:59:40 -07:00
return request ( ' textDocument/completion ' , params )
2019-11-20 15:21:57 -07:00
end
2020-07-19 14:16:12 -07:00
--- Formats the current buffer.
---
2020-08-19 09:17:08 -07:00
--@param options (optional, table) Can be used to specify FormattingOptions.
2020-07-19 14:16:12 -07:00
--- Some unspecified options will be automatically derived from the current
--- Neovim options.
2020-08-19 09:17:08 -07:00
--
--@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
2019-11-20 21:51:44 -07:00
function M . formatting ( options )
2020-05-05 08:23:45 -07:00
local params = util.make_formatting_params ( options )
2019-11-26 06:59:40 -07:00
return request ( ' textDocument/formatting ' , params )
2019-11-20 21:51:44 -07:00
end
2020-08-19 09:17:08 -07:00
--- Performs |vim.lsp.buf.formatting()| synchronously.
2020-07-02 04:09:17 -07:00
---
--- Useful for running on save, to make sure buffer is formatted prior to being
2020-08-19 09:17:08 -07:00
--- 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
2020-05-05 08:23:45 -07:00
function M . formatting_sync ( options , timeout_ms )
local params = util.make_formatting_params ( options )
local result = vim.lsp . buf_request_sync ( 0 , " textDocument/formatting " , params , timeout_ms )
if not result then return end
result = result [ 1 ] . result
2020-09-12 09:39:52 -07:00
if not result then return end
2020-05-05 08:23:45 -07:00
vim.lsp . util.apply_text_edits ( result )
end
2020-08-19 09:17:08 -07:00
--- 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.
2019-11-20 21:51:44 -07:00
function M . range_formatting ( options , start_pos , end_pos )
2020-09-24 12:53:08 -07:00
validate { options = { options , ' t ' , true } }
2020-02-10 23:53:14 -07:00
local sts = vim.bo . softtabstop ;
2019-11-21 16:19:06 -07:00
options = vim.tbl_extend ( ' keep ' , options or { } , {
2020-02-10 23:53:14 -07:00
tabSize = ( sts > 0 and sts ) or ( sts < 0 and vim.bo . shiftwidth ) or vim.bo . tabstop ;
2019-11-26 06:59:40 -07:00
insertSpaces = vim.bo . expandtab ;
2019-11-21 16:19:06 -07:00
} )
2020-09-24 12:53:08 -07:00
local params = util.make_given_range_params ( start_pos , end_pos )
params.options = options
2019-11-26 06:59:40 -07:00
return request ( ' textDocument/rangeFormatting ' , params )
2019-11-20 15:21:57 -07:00
end
2020-08-19 09:17:08 -07:00
--- Renames all references to the symbol under the cursor.
---
--@param new_name (string) If not provided, the user will be prompted for a new
---name using |input()|.
2019-11-20 17:03:32 -07:00
function M . rename ( new_name )
2019-11-20 17:16:36 -07:00
-- 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.
2019-11-21 16:41:32 -07:00
local params = util.make_position_params ( )
2020-06-27 11:10:19 -07:00
new_name = new_name or npcall ( vfn.input , " New Name: " , vfn.expand ( ' <cword> ' ) )
2019-11-20 17:16:36 -07:00
if not ( new_name and # new_name > 0 ) then return end
params.newName = new_name
2019-11-26 06:59:40 -07:00
request ( ' textDocument/rename ' , params )
2019-11-20 17:03:32 -07:00
end
2020-07-19 14:16:12 -07:00
--- Lists all the references to the symbol under the cursor in the quickfix window.
---
2020-08-19 09:17:08 -07:00
--@param context (table) Context for the request
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
2019-11-24 04:01:18 -07:00
function M . references ( context )
validate { context = { context , ' t ' , true } }
local params = util.make_position_params ( )
params.context = context or {
includeDeclaration = true ;
}
params [ vim.type_idx ] = vim.types . dictionary
2019-11-26 06:59:40 -07:00
request ( ' textDocument/references ' , params )
2019-11-24 04:01:18 -07:00
end
2020-07-19 14:16:12 -07:00
--- Lists all symbols in the current buffer in the quickfix window.
---
2020-02-22 05:14:10 -07:00
function M . document_symbol ( )
local params = { textDocument = util.make_text_document_params ( ) }
request ( ' textDocument/documentSymbol ' , params )
end
2020-08-19 09:17:08 -07:00
--@private
2020-07-18 12:10:09 -07:00
local function pick_call_hierarchy_item ( call_hierarchy_items )
if not call_hierarchy_items then return end
if # call_hierarchy_items == 1 then
return call_hierarchy_items [ 1 ]
end
local items = { }
for i , item in ipairs ( call_hierarchy_items ) do
local entry = item.detail or item.name
table.insert ( items , string.format ( " %d. %s " , i , entry ) )
end
local choice = vim.fn . inputlist ( items )
if choice < 1 or choice > # items then
return
end
return choice
end
2020-08-19 09:17:08 -07:00
--- 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|.
2020-07-18 12:10:09 -07:00
function M . incoming_calls ( )
local params = util.make_position_params ( )
request ( ' textDocument/prepareCallHierarchy ' , params , function ( _ , _ , result )
local call_hierarchy_item = pick_call_hierarchy_item ( result )
vim.lsp . buf_request ( 0 , ' callHierarchy/incomingCalls ' , { item = call_hierarchy_item } )
end )
end
2020-08-19 09:17:08 -07:00
--- 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|.
2020-07-18 12:10:09 -07:00
function M . outgoing_calls ( )
local params = util.make_position_params ( )
request ( ' textDocument/prepareCallHierarchy ' , params , function ( _ , _ , result )
local call_hierarchy_item = pick_call_hierarchy_item ( result )
vim.lsp . buf_request ( 0 , ' callHierarchy/outgoingCalls ' , { item = call_hierarchy_item } )
end )
end
2020-07-02 04:09:17 -07:00
--- Lists all symbols in the current workspace in the quickfix window.
---
2020-08-19 09:17:08 -07:00
--- The list is filtered against {query}; if the argument is omitted from the
--- call, the user is prompted to enter a string on the command line. An empty
--- string means no filtering is done.
---
--@param query (string, optional)
2020-05-02 08:56:05 -07:00
function M . workspace_symbol ( query )
query = query or npcall ( vfn.input , " Query: " )
local params = { query = query }
request ( ' workspace/symbol ' , params )
end
2020-02-26 12:10:16 -07:00
--- Send request to server to resolve document highlights for the
--- current text document position. This request can be associated
--- to key mapping or to events such as `CursorHold`, eg:
---
--- <pre>
--- vim.api.nvim_command [[autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()]]
--- vim.api.nvim_command [[autocmd CursorHoldI <buffer> lua vim.lsp.buf.document_highlight()]]
--- vim.api.nvim_command [[autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references()]]
--- </pre>
function M . document_highlight ( )
local params = util.make_position_params ( )
request ( ' textDocument/documentHighlight ' , params )
end
2020-08-19 09:17:08 -07:00
--- Removes document highlights from current buffer.
---
2020-02-26 12:10:16 -07:00
function M . clear_references ( )
util.buf_clear_references ( )
end
2020-08-19 09:17:08 -07:00
--- 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
2020-05-15 16:18:59 -07:00
function M . code_action ( context )
validate { context = { context , ' t ' , true } }
context = context or { diagnostics = util.get_line_diagnostics ( ) }
local params = util.make_range_params ( )
params.context = context
request ( ' textDocument/codeAction ' , params )
end
2020-09-24 12:53:08 -07:00
--- Performs |vim.lsp.buf.code_action()| for a given range.
---
--@param context: (table, optional) Valid `CodeActionContext` object
--@param start_pos ({number, number}, optional) mark-indexed position.
---Defaults to the start of the last visual selection.
--@param end_pos ({number, number}, optional) mark-indexed position.
---Defaults to the end of the last visual selection.
function M . range_code_action ( context , start_pos , end_pos )
validate { context = { context , ' t ' , true } }
context = context or { diagnostics = util.get_line_diagnostics ( ) }
local params = util.make_given_range_params ( start_pos , end_pos )
params.context = context
request ( ' textDocument/codeAction ' , params )
end
2020-08-19 09:17:08 -07:00
--- Executes an LSP server command.
---
--@param command A valid `ExecuteCommandParams` object
--@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
2020-05-15 16:18:59 -07:00
function M . execute_command ( command )
validate {
command = { command.command , ' s ' } ,
arguments = { command.arguments , ' t ' , true }
}
request ( ' workspace/executeCommand ' , command )
end
2019-11-20 15:21:57 -07:00
return M
2019-11-20 17:16:36 -07:00
-- vim:sw=2 ts=2 et