diff options
Diffstat (limited to 'runtime')
| -rw-r--r-- | runtime/doc/lsp.txt | 58 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp.lua | 17 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/buf.lua | 19 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/diagnostic.lua | 63 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/handlers.lua | 59 | ||||
| -rw-r--r-- | runtime/lua/vim/lsp/util.lua | 5 | ||||
| -rw-r--r-- | runtime/lua/vim/shared.lua | 10 |
7 files changed, 174 insertions, 57 deletions
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 111c3ee7f7..62f529b463 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1199,6 +1199,26 @@ clear({bufnr}, {client_id}, {diagnostic_ns}, {sign_ns}) namespace {sign_ns} number|nil Associated sign namespace +disable({bufnr}, {client_id}) *vim.lsp.diagnostic.disable()* + Disable diagnostics for the given buffer and client + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Disable diagnostics for + the given client. The default is to disable + diagnostics for all attached clients. + +enable({bufnr}, {client_id}) *vim.lsp.diagnostic.enable()* + Enable diagnostics for the given buffer and client + + Parameters: ~ + {bufnr} (optional, number): Buffer handle, defaults + to current + {client_id} (optional, number): Enable diagnostics for + the given client. The default is to enable + diagnostics for all attached clients. + get({bufnr}, {client_id}) *vim.lsp.diagnostic.get()* Return associated diagnostics for bufnr @@ -1630,23 +1650,29 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()* ============================================================================== Lua module: vim.lsp.handlers *lsp-handlers* - *vim.lsp.handlers.progress_handler()* -progress_handler({_}, {_}, {params}, {client_id}) - See also: ~ - https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand + *vim.lsp.handlers.hover()* +hover({_}, {method}, {result}, {_}, {_}, {config}) + |lsp-handler| for the method "textDocument/hover" > + + vim.lsp.handlers["textDocument/hover"] = vim.lsp.with( + vim.lsp.handlers.hover, { + -- Use a sharp border with `FloatBorder` highlights + border = "single" + } + ) +< - *vim.lsp.handlers.signature_help()* -signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) Parameters: ~ {config} table Configuration table. • border: (default=nil) • Add borders to the floating window • See |vim.api.nvim_open_win()| - See also: ~ - https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation|lsp-handler| for the method "textDocument/signatureHelp" - The active parameter is highlighted with - |hl-LspSignatureActiveParameter|> + *vim.lsp.handlers.signature_help()* +signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) + |lsp-handler| for the method "textDocument/signatureHelp". The + active parameter is highlighted with + |hl-LspSignatureActiveParameter|. > vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with( vim.lsp.handlers.signature_help, { @@ -1656,6 +1682,12 @@ signature_help({_}, {method}, {result}, {client_id}, {bufnr}, {config}) ) < + Parameters: ~ + {config} table Configuration table. + • border: (default=nil) + • Add borders to the floating window + • See |vim.api.nvim_open_win()| + ============================================================================== Lua module: vim.lsp.util *lsp-util* @@ -1915,14 +1947,14 @@ make_floating_popup_options({width}, {height}, {opts}) *vim.lsp.util.make_formatting_params()* make_formatting_params({options}) - Creates a `FormattingOptions` object for the current buffer - and cursor position. + Creates a `DocumentFormattingParams` object for the current + buffer and cursor position. Parameters: ~ {options} Table with valid `FormattingOptions` entries Return: ~ - `FormattingOptions object + `DocumentFormattingParams` object See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 75faf9bcc7..f5aefc8260 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -590,6 +590,10 @@ end --- as `initializationOptions`. See `initialize` in the LSP spec. --- --@param name (string, default=client-id) Name in log messages. +-- +--@param workspace_folders (table) List of workspace folders passed to the +--- language server. Defaults to root_dir if not set. See `workspaceFolders` in +--- the LSP spec --- --@param get_language_id function(bufnr, filetype) -> language ID as string. --- Defaults to the filetype. @@ -775,6 +779,14 @@ function lsp.start_client(config) off = 'off'; messages = 'messages'; verbose = 'verbose'; } local version = vim.version() + + if not config.workspace_folders then + config.workspace_folders = {{ + uri = vim.uri_from_fname(config.root_dir); + name = string.format("%s", config.root_dir); + }}; + end + local initialize_params = { -- The process Id of the parent process that started the server. Is null if -- the process has not been started by another process. If the parent @@ -815,10 +827,7 @@ function lsp.start_client(config) -- -- workspace folder in the user interface. -- name -- } - workspaceFolders = {{ - uri = vim.uri_from_fname(config.root_dir); - name = string.format("%s", config.root_dir); - }}; + workspaceFolders = config.workspace_folders, } if config.before_init then -- TODO(ashkan) handle errors here. diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index ced1747ee0..29f8d6c3bc 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -422,6 +422,21 @@ function M.clear_references() util.buf_clear_references() end +--- Requests code actions from all clients and calls the handler exactly once +--- with all aggregated results +--@private +local function code_action_request(params) + local bufnr = vim.api.nvim_get_current_buf() + local method = 'textDocument/codeAction' + vim.lsp.buf_request_all(bufnr, method, params, function(results) + local actions = {} + for _, r in pairs(results) do + vim.list_extend(actions, r.result or {}) + end + vim.lsp.handlers[method](nil, method, actions, nil, bufnr) + end) +end + --- Selects a code action from the input list that is available at the current --- cursor position. -- @@ -432,7 +447,7 @@ function M.code_action(context) context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } local params = util.make_range_params() params.context = context - request('textDocument/codeAction', params) + code_action_request(params) end --- Performs |vim.lsp.buf.code_action()| for a given range. @@ -447,7 +462,7 @@ function M.range_code_action(context, start_pos, end_pos) context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } local params = util.make_given_range_params(start_pos, end_pos) params.context = context - request('textDocument/codeAction', params) + code_action_request(params) end --- Executes an LSP server command. diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1342df529f..9a97e5db2f 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -208,6 +208,9 @@ local diagnostic_cache_lines = setmetatable({}, bufnr_and_client_cacher_mt) local diagnostic_cache_counts = setmetatable({}, bufnr_and_client_cacher_mt) local diagnostic_attached_buffers = {} +-- Disabled buffers and clients +local diagnostic_disabled = setmetatable({}, bufnr_and_client_cacher_mt) + local _bufs_waiting_to_update = setmetatable({}, bufnr_and_client_cacher_mt) --- Store Diagnostic[] by line @@ -816,10 +819,7 @@ end ---@param diagnostic_ns number|nil Associated diagnostic namespace ---@param sign_ns number|nil Associated sign namespace function M.clear(bufnr, client_id, diagnostic_ns, sign_ns) - validate { bufnr = { bufnr, 'n' } } - - bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr - + bufnr = get_bufnr(bufnr) if client_id == nil then return vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _) return M.clear(bufnr, iter_client_id) @@ -1092,6 +1092,10 @@ end --@private --- Display diagnostics for the buffer, given a configuration. function M.display(diagnostics, bufnr, client_id, config) + if diagnostic_disabled[bufnr][client_id] then + return + end + config = vim.lsp._with_extend('vim.lsp.diagnostic.on_publish_diagnostics', { signs = true, underline = true, @@ -1282,6 +1286,57 @@ function M.set_loclist(opts) vim.cmd [[lopen]] end end + +--- Disable diagnostics for the given buffer and client +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Disable diagnostics for the given +--- client. The default is to disable diagnostics for all attached +--- clients. +-- Note that when diagnostics are disabled for a buffer, the server will still +-- send diagnostic information and the client will still process it. The +-- diagnostics are simply not displayed to the user. +function M.disable(bufnr, client_id) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.disable(bufnr, client.id) + end) + end + + diagnostic_disabled[bufnr][client_id] = true + M.clear(bufnr, client_id) +end + +--- Enable diagnostics for the given buffer and client +--- @param bufnr (optional, number): Buffer handle, defaults to current +--- @param client_id (optional, number): Enable diagnostics for the given +--- client. The default is to enable diagnostics for all attached +--- clients. +function M.enable(bufnr, client_id) + if not client_id then + return vim.lsp.for_each_buffer_client(bufnr, function(client) + M.enable(bufnr, client.id) + end) + end + + if not diagnostic_disabled[bufnr][client_id] then + return + end + + diagnostic_disabled[bufnr][client_id] = nil + + -- We need to invoke the publishDiagnostics handler directly instead of just + -- calling M.display so that we can preserve any custom configuration options + -- the user may have set with vim.lsp.with. + vim.lsp.handlers["textDocument/publishDiagnostics"]( + nil, + "textDocument/publishDiagnostics", + { + diagnostics = M.get(bufnr, client_id), + uri = vim.uri_from_bufnr(bufnr), + }, + client_id + ) +end -- }}} return M diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 797ff762cb..acd20a3e0b 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -17,13 +17,12 @@ local function err_message(...) api.nvim_command("redraw") end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand M['workspace/executeCommand'] = function() -- Error handling is done implicitly by wrapping all handlers; see end of this file end --- @msg of type ProgressParams --- Basically a token of type number/string +--@private local function progress_handler(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) local client_name = client and client.name or string.format("id=%d", client_id) @@ -59,10 +58,10 @@ local function progress_handler(_, _, params, client_id) vim.api.nvim_command("doautocmd <nomodeline> User LspProgressUpdate") end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress M['$/progress'] = progress_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create M['window/workDoneProgress/create'] = function(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) local token = params.token -- string or number @@ -74,7 +73,7 @@ M['window/workDoneProgress/create'] = function(_, _, params, client_id) return vim.NIL end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest M['window/showMessageRequest'] = function(_, _, params) local actions = params.actions @@ -95,7 +94,7 @@ M['window/showMessageRequest'] = function(_, _, params) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability M['client/registerCapability'] = function(_, _, _, client_id) local warning_tpl = "The language server %s triggers a registerCapability ".. "handler despite dynamicRegistration set to false. ".. @@ -107,7 +106,7 @@ M['client/registerCapability'] = function(_, _, _, client_id) return vim.NIL end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction M['textDocument/codeAction'] = function(_, _, actions) if actions == nil or vim.tbl_isempty(actions) then print("No code actions available") @@ -141,7 +140,7 @@ M['textDocument/codeAction'] = function(_, _, actions) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit M['workspace/applyEdit'] = function(_, _, workspace_edit) if not workspace_edit then return end -- TODO(ashkan) Do something more with label? @@ -155,7 +154,7 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit) } end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration M['workspace/configuration'] = function(_, _, params, client_id) local client = vim.lsp.get_client_by_id(client_id) if not client then @@ -207,34 +206,34 @@ local function response_to_qflist(map_result, entity) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references M['textDocument/references'] = response_to_qflist(util.locations_to_items, 'references') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol M['textDocument/documentSymbol'] = response_to_qflist(util.symbols_to_items, 'document symbols') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol M['workspace/symbol'] = response_to_qflist(util.symbols_to_items, 'symbols') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M['textDocument/rename'] = function(_, _, result) if not result then return end util.apply_workspace_edit(result) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting M['textDocument/rangeFormatting'] = function(_, _, result, _, bufnr) if not result then return end util.apply_text_edits(result, bufnr) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting M['textDocument/formatting'] = function(_, _, result, _, bufnr) if not result then return end util.apply_text_edits(result, bufnr) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion M['textDocument/completion'] = function(_, _, result) if vim.tbl_isempty(result or {}) then return end local row, col = unpack(api.nvim_win_get_cursor(0)) @@ -276,7 +275,7 @@ function M.hover(_, method, result, _, _, config) return util.open_floating_preview(markdown_lines, "markdown", config) end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover M['textDocument/hover'] = M.hover --@private @@ -306,17 +305,17 @@ local function location_handler(_, method, result) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration M['textDocument/declaration'] = location_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition M['textDocument/definition'] = location_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition M['textDocument/typeDefinition'] = location_handler ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation M['textDocument/implementation'] = location_handler ---- |lsp-handler| for the method "textDocument/signatureHelp" ---- The active parameter is highlighted with |hl-LspSignatureActiveParameter| +--- |lsp-handler| for the method "textDocument/signatureHelp". +--- The active parameter is highlighted with |hl-LspSignatureActiveParameter|. --- <pre> --- vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with( --- vim.lsp.handlers.signature_help, { @@ -358,10 +357,10 @@ function M.signature_help(_, method, result, client_id, bufnr, config) return fbuf, fwin end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp M['textDocument/signatureHelp'] = M.signature_help ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight M['textDocument/documentHighlight'] = function(_, _, result, _, bufnr, _) if not result then return end util.buf_highlight_references(bufnr, result) @@ -394,13 +393,13 @@ local make_call_hierarchy_handler = function(direction) end end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/incomingCalls +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls M['callHierarchy/incomingCalls'] = make_call_hierarchy_handler('from') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/outgoingCalls +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls M['callHierarchy/outgoingCalls'] = make_call_hierarchy_handler('to') ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/logMessage +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage M['window/logMessage'] = function(_, _, result, client_id) local message_type = result.type local message = result.message @@ -421,7 +420,7 @@ M['window/logMessage'] = function(_, _, result, client_id) return result end ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/showMessage +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage M['window/showMessage'] = function(_, _, result, client_id) local message_type = result.type local message = result.message diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index f047a12dff..dc15d67e1c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -990,6 +990,7 @@ function M.make_floating_popup_options(width, height, opts) style = 'minimal', width = width, border = opts.border or default_border, + zindex = opts.zindex or 50, } end @@ -1868,10 +1869,10 @@ function M.get_effective_tabstop(bufnr) return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop end ---- Creates a `FormattingOptions` object for the current buffer and cursor position. +--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- --@param options Table with valid `FormattingOptions` entries ---@returns `FormattingOptions object +--@returns `DocumentFormattingParams` object --@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) validate { options = {options, 't', true} } diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 0a663628a5..33c2b2c46c 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -200,6 +200,12 @@ function vim.tbl_isempty(t) return next(t) == nil end +--- we only merge empty tables or tables that are not a list +--@private +local function can_merge(v) + return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) +end + local function tbl_extend(behavior, deep_extend, ...) if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then error('invalid "behavior": '..tostring(behavior)) @@ -219,8 +225,8 @@ local function tbl_extend(behavior, deep_extend, ...) vim.validate{["after the second argument"] = {tbl,'t'}} if tbl then for k, v in pairs(tbl) do - if type(v) == 'table' and deep_extend and not vim.tbl_islist(v) then - ret[k] = tbl_extend(behavior, true, ret[k] or vim.empty_dict(), v) + if deep_extend and can_merge(v) and can_merge(ret[k]) then + ret[k] = tbl_extend(behavior, true, ret[k], v) elseif behavior ~= 'force' and ret[k] ~= nil then if behavior == 'error' then error('key found in more than one map: '..k) |