Move everything to buf & default_callbacks

- Rename builtin_callbacks to default_callbacks and slightly change its
semantics:
  - No longer contains the default implementations. Instead, any
  default_callbacks will be used in preference for our .buf methods.
  - Add this to the docs.
This commit is contained in:
Ashkan Kiani
2019-11-20 16:03:32 -08:00
parent 2d580756ca
commit a4b7004f48
6 changed files with 167 additions and 495 deletions

View File

@@ -346,31 +346,34 @@ vim.lsp.rpc_response_error({code}, [{message}], [{data}])
the server. the server.
================================================================================ ================================================================================
*vim.lsp.builtin_callbacks* *vim.lsp.default_callbacks*
The |vim.lsp.builtin_callbacks| table contains the default |lsp-callbacks| The |vim.lsp.default_callbacks| table contains the default |lsp-callbacks|
that are used when creating a new client. The keys are the LSP method names. that are used when creating a new client. The keys are the LSP method names.
The following requests and notifications have built-in callbacks defined to The following requests and notifications have built-in callbacks defined to
handle the response in an idiomatic way. handle the response in an idiomatic way.
textDocument/completion textDocument/publishDiagnostics
textDocument/declaration
textDocument/definition
textDocument/hover
textDocument/implementation
textDocument/rename
textDocument/signatureHelp
textDocument/typeDefinition
window/logMessage window/logMessage
window/showMessage window/showMessage
You can check these via `vim.tbl_keys(vim.lsp.builtin_callbacks)`. You can check these via `vim.tbl_keys(vim.lsp.default_callbacks)`.
These will be automatically used and can be overridden by users (either by These will be used preferrentially in `vim.lsp.buf` methods when handling
modifying the |vim.lsp.builtin_callbacks| object or on a per-client basis requests. They will also be used when responding to server requests and
by passing in a table via the {callbacks} parameter on |vim.lsp.start_client| notifications.
or |vim.lsp.add_filetype_config|.
Use cases:
- Users can modify this to customize to their preferences.
- UI plugins can modify this by assigning to
`vim.lsp.default_callbacks[method]` so as to provide more specialized
handling, allowing you to leverage the UI capabilities available. UIs should
try to be conscientious of any existing changes the user may have set
already by checking for existing values.
Any callbacks passed directly to `request` methods on a server client will
have the highest precedence, followed by the `default_callbacks`.
More information about callbacks can be found in |lsp-callbacks|. More information about callbacks can be found in |lsp-callbacks|.
@@ -379,8 +382,8 @@ More information about callbacks can be found in |lsp-callbacks|.
Callbacks are functions which are called in a variety of situations by the Callbacks are functions which are called in a variety of situations by the
client. Their signature is `function(err, method, params, client_id)` They can client. Their signature is `function(err, method, params, client_id)` They can
be set by the {callbacks} parameter for |vim.lsp.start_client| and be set by the {callbacks} parameter for |vim.lsp.start_client| or via the
|vim.lsp.add_filetype_config| or via the |vim.lsp.builtin_callbacks|. |vim.lsp.default_callbacks|.
This will be called for: This will be called for:
- notifications from the server, where `err` will always be `nil` - notifications from the server, where `err` will always be `nil`

View File

@@ -1,4 +1,4 @@
local builtin_callbacks = require 'vim.lsp.builtin_callbacks' local default_callbacks = require 'vim.lsp.default_callbacks'
local log = require 'vim.lsp.log' local log = require 'vim.lsp.log'
local lsp_rpc = require 'vim.lsp.rpc' local lsp_rpc = require 'vim.lsp.rpc'
local protocol = require 'vim.lsp.protocol' local protocol = require 'vim.lsp.protocol'
@@ -12,7 +12,8 @@ local validate = vim.validate
local lsp = { local lsp = {
protocol = protocol; protocol = protocol;
builtin_callbacks = builtin_callbacks; default_callbacks = default_callbacks;
buf = require'vim.lsp.buf';
util = util; util = util;
-- Allow raw RPC access. -- Allow raw RPC access.
rpc = lsp_rpc; rpc = lsp_rpc;
@@ -283,7 +284,7 @@ function lsp.start_client(config)
local client_id = next_client_id() local client_id = next_client_id()
local callbacks = tbl_extend("keep", config.callbacks or {}, builtin_callbacks) local callbacks = tbl_extend("keep", config.callbacks or {}, default_callbacks)
-- Copy metatable if it has one. -- Copy metatable if it has one.
if config.callbacks and config.callbacks.__metatable then if config.callbacks and config.callbacks.__metatable then
setmetatable(callbacks, getmetatable(config.callbacks)) setmetatable(callbacks, getmetatable(config.callbacks))
@@ -869,134 +870,8 @@ function lsp.omnifunc(findstart, base)
end end
end end
--- function lsp.client_is_stopped(client_id)
--- FileType based configuration utility return active_clients[client_id] == nil
---
local all_filetype_configs = {}
-- Lookup a filetype config client by its name.
function lsp.get_filetype_client_by_name(name)
local config = all_filetype_configs[name]
if config.client_id then
return active_clients[config.client_id]
end
end
local function start_filetype_config(config)
config.client_id = lsp.start_client(config)
nvim_command(string.format(
"autocmd FileType %s silent lua vim.lsp.buf_attach_client(0, %d)",
table.concat(config.filetypes, ','),
config.client_id))
return config.client_id
end
-- Easy configuration option for common LSP use-cases.
-- This will lazy initialize the client when the filetypes specified are
-- encountered and attach to those buffers.
--
-- The configuration options are the same as |vim.lsp.start_client()|, but
-- with a few additions and distinctions:
--
-- Additional parameters:
-- - filetype: {string} or {list} of filetypes to attach to.
-- - name: A unique string among all other servers configured with
-- |vim.lsp.add_filetype_config|.
--
-- Differences:
-- - root_dir: will default to |getcwd()|
--
function lsp.add_filetype_config(config)
-- Additional defaults.
-- Keep a copy of the user's input for debugging reasons.
local user_config = config
config = tbl_extend("force", {}, user_config)
config.root_dir = config.root_dir or uv.cwd()
-- Validate config.
validate_client_config(config)
validate {
name = { config.name, 's' };
}
assert(config.filetype, "config must have 'filetype' key")
local filetypes
if type(config.filetype) == 'string' then
filetypes = { config.filetype }
elseif type(config.filetype) == 'table' then
filetypes = config.filetype
assert(not tbl_isempty(filetypes), "config.filetype must not be an empty table")
else
error("config.filetype must be a string or a list of strings")
end
if all_filetype_configs[config.name] then
-- If the client exists, then it is likely that they are doing some kind of
-- reload flow, so let's not throw an error here.
if all_filetype_configs[config.name].client_id then
-- TODO log here? It might be unnecessarily annoying.
return
end
error(string.format('A configuration with the name %q already exists. They must be unique', config.name))
end
all_filetype_configs[config.name] = tbl_extend("keep", config, {
client_id = nil;
filetypes = filetypes;
user_config = user_config;
})
nvim_command(string.format(
"autocmd FileType %s ++once silent lua vim.lsp._start_filetype_config_client(%q)",
table.concat(filetypes, ','),
config.name))
end
-- Create a copy of an existing configuration, and override config with values
-- from new_config.
-- This is useful if you wish you create multiple LSPs with different root_dirs
-- or other use cases.
--
-- You can specify a new unique name, but if you do not, a unique name will be
-- created like `name-dup_count`.
--
-- existing_name: the name of the existing config to copy.
-- new_config: the new configuration options. @see |vim.lsp.start_client()|.
-- @returns string the new name.
function lsp.copy_filetype_config(existing_name, new_config)
local config = all_filetype_configs[existing_name]
or error(string.format("Configuration with name %q doesn't exist", existing_name))
config = tbl_extend("force", config, new_config or {})
config.client_id = nil
config.original_config_name = existing_name
-- If the user didn't rename it, we will.
if config.name == existing_name then
-- Create a new, unique name.
local duplicate_count = 0
for _, conf in pairs(all_filetype_configs) do
if conf.original_config_name == existing_name then
duplicate_count = duplicate_count + 1
end
end
config.name = string.format("%s-%d", existing_name, duplicate_count + 1)
end
print("New config name:", config.name)
lsp.add_filetype_config(config)
return config.name
end
-- Autocmd handler to actually start the client when an applicable filetype is
-- encountered.
function lsp._start_filetype_config_client(name)
local config = all_filetype_configs[name]
-- If it exists and is running, don't make it again.
if config.client_id and active_clients[config.client_id] then
-- TODO log here?
return
end
lsp.buf_attach_client(0, start_filetype_config(config))
return config.client_id
end end
--- ---

View File

@@ -33,7 +33,7 @@ end
local function request(method, params, callback) local function request(method, params, callback)
-- TODO(ashkan) enable this. -- TODO(ashkan) enable this.
-- callback = vim.lsp.default_callback[method] or callback -- callback = vim.lsp.default_callbacks[method] or callback
validate { validate {
method = {method, 's'}; method = {method, 's'};
callback = {callback, 'f'}; callback = {callback, 'f'};
@@ -172,9 +172,78 @@ function M.implementation()
request('textDocument/implementation', params, location_callback) request('textDocument/implementation', params, location_callback)
end end
--- Convert SignatureHelp response to preview contents.
-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
local function signature_help_to_preview_contents(input)
if not input.signatures then
return
end
--The active signature. If omitted or the value lies outside the range of
--`signatures` the value defaults to zero or is ignored if `signatures.length
--=== 0`. Whenever possible implementors should make an active decision about
--the active signature and shouldn't rely on a default value.
local contents = {}
local active_signature = input.activeSignature or 0
-- If the activeSignature is not inside the valid range, then clip it.
if active_signature >= #input.signatures then
active_signature = 0
end
local signature = input.signatures[active_signature + 1]
if not signature then
return
end
vim.list_extend(contents, split_lines(signature.label))
if signature.documentation then
util.convert_input_to_markdown_lines(signature.documentation, contents)
end
if input.parameters then
local active_parameter = input.activeParameter or 0
-- If the activeParameter is not inside the valid range, then clip it.
if active_parameter >= #input.parameters then
active_parameter = 0
end
local parameter = signature.parameters and signature.parameters[active_parameter]
if parameter then
--[=[
--Represents a parameter of a callable-signature. A parameter can
--have a label and a doc-comment.
interface ParameterInformation {
--The label of this parameter information.
--
--Either a string or an inclusive start and exclusive end offsets within its containing
--signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
--string representation as `Position` and `Range` does.
--
--*Note*: a label of type string should be a substring of its containing signature label.
--Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
label: string | [number, number];
--The human-readable doc-comment of this parameter. Will be shown
--in the UI but can be omitted.
documentation?: string | MarkupContent;
}
--]=]
-- TODO highlight parameter
if parameter.documentation then
util.convert_input_to_markdown_lines(parameter.documentation, contents)
end
end
end
return contents
end
function M.signature_help() function M.signature_help()
local params = protocol.make_text_document_position_params() local params = protocol.make_text_document_position_params()
request('textDocument/signatureHelp', params, location_callback) focusable_preview('textDocument/signatureHelp', params, function(result)
if not (result and result.signatures and result.signatures[1]) then return end
-- TODO show empty popup when signatures is empty?
local lines = signature_help_to_preview_contents(result)
lines = util.trim_empty_lines(lines)
if vim.tbl_isempty(lines) then
return { 'No signature available' }
end
return lines, util.try_trim_markdown_code_blocks(lines)
end)
end end
-- TODO(ashkan) ? -- TODO(ashkan) ?
@@ -195,4 +264,17 @@ end
function M.range_formatting() function M.range_formatting()
end end
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 = protocol.make_text_document_position_params()
new_name = new_name or npcall(vfn.input, "New Name: ")
if not (new_name and #new_name > 0) then return end
params.newName = new_name
request('textDocument/rename', params, function(_, _, result)
if not result then return end
util.workspace_apply_workspace_edit(result)
end)
end
return M return M

View File

@@ -1,344 +0,0 @@
--- Implements the following default callbacks:
--
-- vim.api.nvim_buf_set_lines(0, 0, 0, false, vim.tbl_keys(vim.lsp.builtin_callbacks))
--
-- textDocument/completion
-- textDocument/declaration
-- textDocument/definition
-- textDocument/hover
-- textDocument/implementation
-- textDocument/publishDiagnostics
-- textDocument/rename
-- textDocument/signatureHelp
-- textDocument/typeDefinition
-- TODO codeLens/resolve
-- TODO completionItem/resolve
-- TODO documentLink/resolve
-- TODO textDocument/codeAction
-- TODO textDocument/codeLens
-- TODO textDocument/documentHighlight
-- TODO textDocument/documentLink
-- TODO textDocument/documentSymbol
-- TODO textDocument/formatting
-- TODO textDocument/onTypeFormatting
-- TODO textDocument/rangeFormatting
-- TODO textDocument/references
-- window/logMessage
-- window/showMessage
local log = require 'vim.lsp.log'
local protocol = require 'vim.lsp.protocol'
local util = require 'vim.lsp.util'
local api = vim.api
local function split_lines(value)
return vim.split(value, '\n', true)
end
local builtin_callbacks = {}
-- textDocument/completion
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
builtin_callbacks['textDocument/completion'] = function(_, _, result)
if not result or vim.tbl_isempty(result) then
return
end
local pos = api.nvim_win_get_cursor(0)
local row, col = pos[1], pos[2]
local line = assert(api.nvim_buf_get_lines(0, row-1, row, false)[1])
local line_to_cursor = line:sub(col+1)
local matches = util.text_document_completion_list_to_complete_items(result, line_to_cursor)
local match_result = vim.fn.matchstrpos(line_to_cursor, '\\k\\+$')
local match_start, match_finish = match_result[2], match_result[3]
vim.fn.complete(col + 1 - (match_finish - match_start), matches)
end
-- textDocument/rename
builtin_callbacks['textDocument/rename'] = function(_, _, result)
if not result then return end
util.workspace_apply_workspace_edit(result)
end
builtin_callbacks['textDocument/publishDiagnostics'] = function(_, _, result)
if not result then return end
local uri = result.uri
local bufnr = vim.uri_to_bufnr(uri)
if not bufnr then
api.nvim_err_writeln(string.format("LSP.publishDiagnostics: Couldn't find buffer for %s", uri))
return
end
util.buf_clear_diagnostics(bufnr)
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
util.buf_diagnostics_underline(bufnr, result.diagnostics)
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
-- util.buf_loclist(bufnr, result.diagnostics)
end
local function focusable_popup()
local popup_win
return function(winnr)
if popup_win and api.nvim_win_is_valid(popup_win) then
if api.nvim_get_current_win() == popup_win then
api.nvim_command("wincmd p")
else
api.nvim_set_current_win(popup_win)
end
return
end
popup_win = winnr
end
end
local hover_popup = focusable_popup()
local function trim_empty_lines(lines)
local result = {}
for _, line in ipairs(lines) do
if #line > 0 then
table.insert(result, line)
end
end
return result
end
-- Accepts markdown lines and tries to reduce it to a filetype if it is
-- just a single code block.
local function try_trim_code_blocks(lines)
local language_id = lines[1]:match("^```(.*)")
if language_id then
local has_inner_code_fence = false
for i = 2, (#lines - 1) do
local line = lines[i]
if line:sub(1,3) == '```' then
has_inner_code_fence = true
break
end
end
-- No inner code fences + starting with code fence = hooray.
if not has_inner_code_fence then
table.remove(lines, 1)
table.remove(lines)
return lines, language_id
end
end
return lines, 'markdown'
end
-- textDocument/hover
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_hover
-- @params MarkedString | MarkedString[] | MarkupContent
builtin_callbacks['textDocument/hover'] = function(_, _, result)
if result == nil or vim.tbl_isempty(result) then
return
end
if result.contents ~= nil then
local markdown_lines = util.convert_input_to_markdown_lines(result.contents)
markdown_lines = trim_empty_lines(markdown_lines)
if vim.tbl_isempty(markdown_lines) then
markdown_lines = { 'No information available' }
end
local _, winnr = util.open_floating_preview(try_trim_code_blocks(markdown_lines))
hover_popup(winnr)
end
end
builtin_callbacks['textDocument/peekDefinition'] = function(_, _, result)
if result == nil or vim.tbl_isempty(result) then return end
-- TODO(ashkan) what to do with multiple locations?
result = result[1]
local bufnr = vim.uri_to_bufnr(result.uri)
assert(bufnr)
local start = result.range.start
local finish = result.range["end"]
util.open_floating_peek_preview(bufnr, start, finish, { offset_x = 1 })
util.open_floating_preview({"*Peek:*", string.rep(" ", finish.character - start.character + 1) }, 'markdown', { offset_y = -(finish.line - start.line) })
end
--- Convert SignatureHelp response to preview contents.
-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
local function signature_help_to_preview_contents(input)
if not input.signatures then
return
end
--The active signature. If omitted or the value lies outside the range of
--`signatures` the value defaults to zero or is ignored if `signatures.length
--=== 0`. Whenever possible implementors should make an active decision about
--the active signature and shouldn't rely on a default value.
local contents = {}
local active_signature = input.activeSignature or 0
-- If the activeSignature is not inside the valid range, then clip it.
if active_signature >= #input.signatures then
active_signature = 0
end
local signature = input.signatures[active_signature + 1]
if not signature then
return
end
vim.list_extend(contents, split_lines(signature.label))
if signature.documentation then
util.convert_input_to_markdown_lines(signature.documentation, contents)
end
if input.parameters then
local active_parameter = input.activeParameter or 0
-- If the activeParameter is not inside the valid range, then clip it.
if active_parameter >= #input.parameters then
active_parameter = 0
end
local parameter = signature.parameters and signature.parameters[active_parameter]
if parameter then
--[=[
--Represents a parameter of a callable-signature. A parameter can
--have a label and a doc-comment.
interface ParameterInformation {
--The label of this parameter information.
--
--Either a string or an inclusive start and exclusive end offsets within its containing
--signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
--string representation as `Position` and `Range` does.
--
--*Note*: a label of type string should be a substring of its containing signature label.
--Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
label: string | [number, number];
--The human-readable doc-comment of this parameter. Will be shown
--in the UI but can be omitted.
documentation?: string | MarkupContent;
}
--]=]
-- TODO highlight parameter
if parameter.documentation then
util.convert_input_to_markdown_lines(parameter.documentation, contents)
end
end
end
return contents
end
-- textDocument/signatureHelp
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_signatureHelp
builtin_callbacks['textDocument/signatureHelp'] = function(_, _, result)
if result == nil or vim.tbl_isempty(result) then
return
end
-- TODO show empty popup when signatures is empty?
if #result.signatures > 0 then
local markdown_lines = signature_help_to_preview_contents(result)
if vim.tbl_isempty(markdown_lines) then
markdown_lines = { 'No signature available' }
end
util.open_floating_preview(markdown_lines, 'markdown')
end
end
local function update_tagstack()
local bufnr = api.nvim_get_current_buf()
local line = vim.fn.line('.')
local col = vim.fn.col('.')
local tagname = vim.fn.expand('<cWORD>')
local item = { bufnr = bufnr, from = { bufnr, line, col, 0 }, tagname = tagname }
local winid = vim.fn.win_getid()
local tagstack = vim.fn.gettagstack(winid)
local action
if tagstack.length == tagstack.curidx then
action = 'r'
tagstack.items[tagstack.curidx] = item
elseif tagstack.length > tagstack.curidx then
action = 'r'
if tagstack.curidx > 1 then
tagstack.items = table.insert(tagstack.items[tagstack.curidx - 1], item)
else
tagstack.items = { item }
end
else
action = 'a'
tagstack.items = { item }
end
tagstack.curidx = tagstack.curidx + 1
vim.fn.settagstack(winid, tagstack, action)
end
local function handle_location(result)
-- We can sometimes get a list of locations, so set the first value as the
-- only value we want to handle
-- TODO(ashkan) was this correct^? We could use location lists.
if result[1] ~= nil then
result = result[1]
end
if result.uri == nil then
api.nvim_err_writeln('[LSP] Could not find a valid location')
return
end
local result_file = vim.uri_to_fname(result.uri)
local bufnr = vim.fn.bufadd(result_file)
update_tagstack()
api.nvim_set_current_buf(bufnr)
local start = result.range.start
api.nvim_win_set_cursor(0, {start.line + 1, start.character})
end
local function location_callback(_, method, result)
if result == nil or vim.tbl_isempty(result) then
local _ = log.info() and log.info(method, 'No location found')
return nil
end
handle_location(result)
return true
end
local location_callbacks = {
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_declaration
'textDocument/declaration';
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_definition
'textDocument/definition';
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation
'textDocument/implementation';
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_typeDefinition
'textDocument/typeDefinition';
}
for _, location_method in ipairs(location_callbacks) do
builtin_callbacks[location_method] = location_callback
end
local function log_message(_, _, result, client_id)
local message_type = result.type
local message = result.message
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
api.nvim_err_writeln(string.format("LSP[%s] client has shut down after sending the message", client_name))
end
if message_type == protocol.MessageType.Error then
-- Might want to not use err_writeln,
-- but displaying a message with red highlights or something
api.nvim_err_writeln(string.format("LSP[%s] %s", client_name, message))
else
local message_type_name = protocol.MessageType[message_type]
api.nvim_out_write(string.format("LSP[%s][%s] %s\n", client_name, message_type_name, message))
end
return result
end
builtin_callbacks['window/showMessage'] = log_message
builtin_callbacks['window/logMessage'] = log_message
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(builtin_callbacks) do
builtin_callbacks[k] = function(err, method, params, client_id)
local _ = log.debug() and log.debug('builtin_callback', method, { params = params, client_id = client_id, err = err })
if err then
error(tostring(err))
end
return fn(err, method, params, client_id)
end
end
return builtin_callbacks
-- vim:sw=2 ts=2 et

View File

@@ -0,0 +1,57 @@
local log = require 'vim.lsp.log'
local protocol = require 'vim.lsp.protocol'
local util = require 'vim.lsp.util'
local api = vim.api
local M = {}
M['textDocument/publishDiagnostics'] = function(_, _, result)
if not result then return end
local uri = result.uri
local bufnr = vim.uri_to_bufnr(uri)
if not bufnr then
api.nvim_err_writeln(string.format("LSP.publishDiagnostics: Couldn't find buffer for %s", uri))
return
end
util.buf_clear_diagnostics(bufnr)
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
util.buf_diagnostics_underline(bufnr, result.diagnostics)
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
-- util.buf_loclist(bufnr, result.diagnostics)
end
local function log_message(_, _, result, client_id)
local message_type = result.type
local message = result.message
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
api.nvim_err_writeln(string.format("LSP[%s] client has shut down after sending the message", client_name))
end
if message_type == protocol.MessageType.Error then
-- Might want to not use err_writeln,
-- but displaying a message with red highlights or something
api.nvim_err_writeln(string.format("LSP[%s] %s", client_name, message))
else
local message_type_name = protocol.MessageType[message_type]
api.nvim_out_write(string.format("LSP[%s][%s] %s\n", client_name, message_type_name, message))
end
return result
end
M['window/showMessage'] = log_message
M['window/logMessage'] = log_message
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(M) do
M[k] = function(err, method, params, client_id)
local _ = log.debug() and log.debug('default_callback', method, { params = params, client_id = client_id, err = err })
if err then
error(tostring(err))
end
return fn(err, method, params, client_id)
end
end
return M
-- vim:sw=2 ts=2 et

View File

@@ -10,7 +10,6 @@ end
--[=[ --[=[
-- Useful for interfacing with: -- Useful for interfacing with:
-- https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-14.md
-- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md -- 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]]