local vim = vim local validate = vim.validate local api = vim.api local vfn = vim.fn local util = require 'vim.lsp.util' local list_extend = vim.list_extend local M = {} --@private --- Returns nil if {status} is false or nil, otherwise returns the rest of the --- arguments. local function ok_or_nil(status, ...) if not status then return end return ... end --@private --- Swallows errors. --- --@param fn Function to run --@param ... Function arguments --@returns Result of `fn(...)` if there are no errors, otherwise nil. --- Returns nil if errors occur during {fn}, otherwise returns local function npcall(fn, ...) return ok_or_nil(pcall(fn, ...)) end --@private --- Sends an async request to all active clients attached to the current --- buffer. --- --@param method (string) LSP method name --@param params (optional, table) Parameters to send to the server --@param callback (optional, functionnil) Handler -- `function(err, method, params, client_id)` for this request. Defaults -- to the client callback in `client.callbacks`. See |lsp-callbacks|. -- --@returns 2-tuple: --- - Map of client-id:request-id pairs for all successful requests. --- - Function which can be used to cancel all the requests. You could instead --- iterate all clients and call their `cancel_request()` methods. --- --@see |vim.lsp.buf_request()| local function request(method, params, callback) validate { method = {method, 's'}; callback = {callback, 'f', true}; } return vim.lsp.buf_request(0, method, params, callback) end --- Checks whether the language servers attached to the current buffer are --- ready. --- --@returns `true` if server responds. function M.server_ready() return not not vim.lsp.buf_notify(0, "window/progress", {}) end --- Displays hover information about the symbol under the cursor in a floating --- window. Calling the function twice will jump into the floating window. function M.hover() local params = util.make_position_params() request('textDocument/hover', params) end --- Jumps to the declaration of the symbol under the cursor. --- function M.declaration() local params = util.make_position_params() request('textDocument/declaration', params) end --- Jumps to the definition of the symbol under the cursor. --- function M.definition() local params = util.make_position_params() request('textDocument/definition', params) end --- Jumps to the definition of the type of the symbol under the cursor. --- function M.type_definition() local params = util.make_position_params() request('textDocument/typeDefinition', params) end --- Lists all the implementations for the symbol under the cursor in the --- quickfix window. function M.implementation() local params = util.make_position_params() request('textDocument/implementation', params) end --- Displays signature information about the symbol under the cursor in a --- floating window. function M.signature_help() local params = util.make_position_params() request('textDocument/signatureHelp', params) end --- Retrieves the completion items at the current cursor position. Can only be --- called in Insert mode. --- --@param context (context support not yet implemented) Additional information --- about the context in which a completion was triggered (how it was triggered, --- and by which trigger character, if applicable) --- --@see |vim.lsp.protocol.constants.CompletionTriggerKind| function M.completion(context) local params = util.make_position_params() params.context = context return request('textDocument/completion', params) end --- Formats the current buffer. --- --@param options (optional, table) Can be used to specify FormattingOptions. --- Some unspecified options will be automatically derived from the current --- Neovim options. -- --@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting function M.formatting(options) local params = util.make_formatting_params(options) return request('textDocument/formatting', params) end --- Performs |vim.lsp.buf.formatting()| synchronously. --- --- Useful for running on save, to make sure buffer is formatted prior to being --- saved. {timeout_ms} is passed on to |vim.lsp.buf_request_sync()|. Example: --- ---
--- vim.api.nvim_command[[autocmd BufWritePre--- --@param options Table with valid `FormattingOptions` entries --@param timeout_ms (number) Request timeout function M.formatting_sync(options, timeout_ms) local params = util.make_formatting_params(options) local result = vim.lsp.buf_request_sync(0, "textDocument/formatting", params, timeout_ms) if not result then return end result = result[1].result vim.lsp.util.apply_text_edits(result) end --- Formats a given range. --- --@param options Table with valid `FormattingOptions` entries. --@param start_pos ({number, number}, optional) mark-indexed position. ---Defaults to the start of the last visual selection. --@param start_pos ({number, number}, optional) mark-indexed position. ---Defaults to the end of the last visual selection. function M.range_formatting(options, start_pos, end_pos) validate { options = {options, 't', true}; start_pos = {start_pos, 't', true}; end_pos = {end_pos, 't', true}; } local sts = vim.bo.softtabstop; options = vim.tbl_extend('keep', options or {}, { tabSize = (sts > 0 and sts) or (sts < 0 and vim.bo.shiftwidth) or vim.bo.tabstop; insertSpaces = vim.bo.expandtab; }) local A = list_extend({}, start_pos or api.nvim_buf_get_mark(0, '<')) local B = list_extend({}, end_pos or api.nvim_buf_get_mark(0, '>')) -- convert to 0-index A[1] = A[1] - 1 B[1] = B[1] - 1 -- account for encoding. if A[2] > 0 then A = {A[1], util.character_offset(0, A[1], A[2])} end if B[2] > 0 then B = {B[1], util.character_offset(0, B[1], B[2])} end local params = { textDocument = { uri = vim.uri_from_bufnr(0) }; range = { start = { line = A[1]; character = A[2]; }; ["end"] = { line = B[1]; character = B[2]; }; }; options = options; } return request('textDocument/rangeFormatting', params) end --- Renames all references to the symbol under the cursor. --- --@param new_name (string) If not provided, the user will be prompted for a new ---name using |input()|. function M.rename(new_name) -- TODO(ashkan) use prepareRename -- * result: [`Range`](#range) \| `{ range: Range, placeholder: string }` \| `null` describing the range of the string to rename and optionally a placeholder text of the string content to be renamed. If `null` is returned then it is deemed that a 'textDocument/rename' request is not valid at the given position. local params = util.make_position_params() new_name = new_name or npcall(vfn.input, "New Name: ", vfn.expand('lua vim.lsp.buf.formatting_sync()]] ---
--- vim.api.nvim_command [[autocmd CursorHoldfunction M.document_highlight() local params = util.make_position_params() request('textDocument/documentHighlight', params) end --- Removes document highlights from current buffer. --- function M.clear_references() util.buf_clear_references() end --- Selects a code action from the input list that is available at the current --- cursor position. -- --@param context: (table, optional) Valid `CodeActionContext` object --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction function M.code_action(context) validate { context = { context, 't', true } } context = context or { diagnostics = util.get_line_diagnostics() } local params = util.make_range_params() params.context = context request('textDocument/codeAction', params) end --- Executes an LSP server command. --- --@param command A valid `ExecuteCommandParams` object --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand function M.execute_command(command) validate { command = { command.command, 's' }, arguments = { command.arguments, 't', true } } request('workspace/executeCommand', command) end return M -- vim:sw=2 ts=2 etlua vim.lsp.buf.document_highlight()]] --- vim.api.nvim_command [[autocmd CursorHoldI lua vim.lsp.buf.document_highlight()]] --- vim.api.nvim_command [[autocmd CursorMoved lua vim.lsp.buf.clear_references()]] ---