aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/lua/vim/lsp.lua32
-rw-r--r--runtime/lua/vim/lsp/client.lua25
-rw-r--r--runtime/lua/vim/lsp/codelens.lua4
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua4
-rw-r--r--runtime/lua/vim/lsp/handlers.lua9
-rw-r--r--runtime/lua/vim/lsp/inlay_hint.lua4
-rw-r--r--runtime/lua/vim/lsp/log.lua206
-rw-r--r--runtime/lua/vim/lsp/rpc.lua42
8 files changed, 140 insertions, 186 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index dc50ab0267..7d8b7e50a3 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -798,9 +798,7 @@ function lsp.start_client(config)
---@param method (string) LSP method name
---@param params (table) The parameters for that method.
function dispatch.notification(method, params)
- if log.trace() then
- log.trace('notification', method, params)
- end
+ log.trace('notification', method, params)
local handler = resolve_handler(method)
if handler then
-- Method name is provided here for convenience.
@@ -816,19 +814,13 @@ function lsp.start_client(config)
---@return any result
---@return lsp.ResponseError error code and message set in case an exception happens during the request.
function dispatch.server_request(method, params)
- if log.trace() then
- log.trace('server_request', method, params)
- end
+ log.trace('server_request', method, params)
local handler = resolve_handler(method)
if handler then
- if log.trace() then
- log.trace('server_request: found handler for', method)
- end
+ log.trace('server_request: found handler for', method)
return handler(nil, params, { method = method, client_id = client_id })
end
- if log.warn() then
- log.warn('server_request: no handler found for', method)
- end
+ log.warn('server_request: no handler found for', method)
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
@@ -836,9 +828,7 @@ function lsp.start_client(config)
--- @param code integer Error code
--- @param err any Error arguments
local function write_error(code, err)
- if log.error() then
- log.error(log_prefix, 'on_error', { code = lsp.client_errors[code], err = err })
- end
+ 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))
end
@@ -854,9 +844,7 @@ function lsp.start_client(config)
if config.on_error then
local status, usererr = pcall(config.on_error, code, err)
if not status then
- if log.error() then
- log.error(log_prefix, 'user on_error failed', { err = usererr })
- end
+ log.error(log_prefix, 'user on_error failed', { err = usererr })
err_message(log_prefix, ' user on_error failed: ', tostring(usererr))
end
end
@@ -1042,9 +1030,7 @@ function lsp.buf_attach_client(bufnr, client_id)
})
bufnr = resolve_bufnr(bufnr)
if not api.nvim_buf_is_loaded(bufnr) then
- if log.warn() then
- log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
- end
+ log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
return false
end
local buffer_client_ids = all_buffer_active_clients[bufnr]
@@ -1504,9 +1490,7 @@ end
--- - findstart=0: column where the completion starts, or -2 or -3
--- - findstart=1: list of matches (actually just calls |complete()|)
function lsp.omnifunc(findstart, base)
- if log.debug() then
- log.debug('omnifunc.findstart', { findstart = findstart, base = base })
- end
+ log.debug('omnifunc.findstart', { findstart = findstart, base = base })
return vim.lsp._completion.omnifunc(findstart, base)
end
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index 36c3a4225e..0bcbb35be6 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -244,9 +244,7 @@ function Client:initialize(cb)
end
end
- if log.trace() then
- log.trace(self._log_prefix, 'initialize_params', initialize_params)
- end
+ log.trace(self._log_prefix, 'initialize_params', initialize_params)
local rpc = self.rpc
@@ -278,13 +276,12 @@ function Client:initialize(cb)
self:write_error(lsp.client_errors.ON_INIT_CALLBACK_ERROR, err)
end
end
- if log.info() then
- log.info(
- self._log_prefix,
- 'server_capabilities',
- { server_capabilities = self.server_capabilities }
- )
- end
+
+ log.info(
+ self._log_prefix,
+ 'server_capabilities',
+ { server_capabilities = self.server_capabilities }
+ )
cb()
end)
@@ -340,9 +337,7 @@ function Client:_request(method, params, handler, bufnr)
changetracking.flush(self, bufnr)
local version = lsp.util.buf_versions[bufnr]
bufnr = resolve_bufnr(bufnr)
- if log.debug() then
- log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr)
- end
+ log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr)
local success, request_id = self.rpc.request(method, params, function(err, result)
local context = {
method = method,
@@ -635,9 +630,7 @@ end
--- @param code integer Error code
--- @param err any Error arguments
function Client:write_error(code, err)
- if log.error() then
- log.error(self._log_prefix, 'on_error', { code = lsp.client_errors[code], err = err })
- end
+ log.error(self._log_prefix, 'on_error', { code = lsp.client_errors[code], err = err })
err_message(self._log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err))
end
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index a045a6bad4..61e3448024 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -262,9 +262,7 @@ end
function M.on_codelens(err, result, ctx, _)
if err then
active_refreshes[assert(ctx.bufnr)] = nil
- if log.error() then
- log.error('codelens', err)
- end
+ log.error('codelens', err)
return
end
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 036b0e6151..aa812fa78c 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -35,7 +35,7 @@ local function severity_vim_to_lsp(severity)
return severity
end
----@param lines string[]
+---@param lines string[]?
---@param lnum integer
---@param col integer
---@param offset_encoding string
@@ -55,7 +55,7 @@ local function line_byte_from_position(lines, lnum, col, offset_encoding)
end
---@param bufnr integer
----@return string[]
+---@return string[]?
local function get_buf_lines(bufnr)
if vim.api.nvim_buf_is_loaded(bufnr) then
return vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 26a71487e2..2fa539d963 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -413,9 +413,7 @@ M[ms.textDocument_hover] = M.hover
---(`textDocument/definition` can return `Location` or `Location[]`
local function location_handler(_, result, ctx, config)
if result == nil or vim.tbl_isempty(result) then
- if log.info() then
- log.info(ctx.method, 'No location found')
- end
+ log.info(ctx.method, 'No location found')
return nil
end
local client = assert(vim.lsp.get_client_by_id(ctx.client_id))
@@ -649,13 +647,14 @@ end
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(M) do
M[k] = function(err, result, ctx, config)
- local _ = log.trace()
- and log.trace('default_handler', ctx.method, {
+ if log.trace() then
+ log.trace('default_handler', ctx.method, {
err = err,
result = result,
ctx = vim.inspect(ctx),
config = config,
})
+ end
if err then
-- LSP spec:
diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua
index 62138c0edf..49dc35fdf6 100644
--- a/runtime/lua/vim/lsp/inlay_hint.lua
+++ b/runtime/lua/vim/lsp/inlay_hint.lua
@@ -22,9 +22,7 @@ local augroup = api.nvim_create_augroup('vim_lsp_inlayhint', {})
---@private
function M.on_inlayhint(err, result, ctx, _)
if err then
- if log.error() then
- log.error('inlayhint', err)
- end
+ log.error('inlayhint', err)
return
end
local bufnr = assert(ctx.bufnr)
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 00433474fe..a9d49bc8f4 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -12,130 +12,130 @@ log.levels = vim.deepcopy(vim.log.levels)
-- Default log level is warn.
local current_log_level = log.levels.WARN
+
local log_date_format = '%F %H:%M:%S'
-local format_func = function(arg)
+
+local function format_func(arg)
return vim.inspect(arg, { newline = '' })
end
-do
- local function notify(msg, level)
- if vim.in_fast_event() then
- vim.schedule(function()
- vim.notify(msg, level)
- end)
- else
+local function notify(msg, level)
+ if vim.in_fast_event() then
+ vim.schedule(function()
vim.notify(msg, level)
- end
+ end)
+ else
+ vim.notify(msg, level)
end
+end
+
+local logfilename = vim.fs.joinpath(vim.fn.stdpath('log'), 'lsp.log')
+
+-- TODO: Ideally the directory should be created in open_logfile(), right
+-- before opening the log file, but open_logfile() can be called from libuv
+-- callbacks, where using fn.mkdir() is not allowed.
+vim.fn.mkdir(vim.fn.stdpath('log'), 'p')
+
+--- Returns the log filename.
+---@return string log filename
+function log.get_filename()
+ return logfilename
+end
+
+--- @type file*?, string?
+local logfile, openerr
- local path_sep = vim.uv.os_uname().version:match('Windows') and '\\' or '/'
- local function path_join(...)
- return table.concat(vim.tbl_flatten({ ... }), path_sep)
+--- Opens log file. Returns true if file is open, false on error
+local function open_logfile()
+ -- Try to open file only once
+ if logfile then
+ return true
+ end
+ if openerr then
+ return false
end
- local logfilename = path_join(vim.fn.stdpath('log'), 'lsp.log')
- -- TODO: Ideally the directory should be created in open_logfile(), right
- -- before opening the log file, but open_logfile() can be called from libuv
- -- callbacks, where using fn.mkdir() is not allowed.
- vim.fn.mkdir(vim.fn.stdpath('log'), 'p')
+ logfile, openerr = io.open(logfilename, 'a+')
+ if not logfile then
+ local err_msg = string.format('Failed to open LSP client log file: %s', openerr)
+ notify(err_msg, vim.log.levels.ERROR)
+ return false
+ end
- --- Returns the log filename.
- ---@return string log filename
- function log.get_filename()
- return logfilename
+ local log_info = vim.uv.fs_stat(logfilename)
+ if log_info and log_info.size > 1e9 then
+ local warn_msg = string.format(
+ 'LSP client log is large (%d MB): %s',
+ log_info.size / (1000 * 1000),
+ logfilename
+ )
+ notify(warn_msg)
end
- local logfile, openerr
- --- Opens log file. Returns true if file is open, false on error
- local function open_logfile()
- -- Try to open file only once
- if logfile then
+ -- Start message for logging
+ logfile:write(string.format('[START][%s] LSP logging initiated\n', os.date(log_date_format)))
+ return true
+end
+
+for level, levelnr in pairs(log.levels) do
+ -- Also export the log level on the root object.
+ log[level] = levelnr
+end
+
+vim.tbl_add_reverse_lookup(log.levels)
+
+--- @param level string
+--- @param levelnr integer
+--- @return fun(...:any): boolean?
+local function create_logger(level, levelnr)
+ return function(...)
+ if levelnr < current_log_level then
+ return false
+ end
+ local argc = select('#', ...)
+ if argc == 0 then
return true
end
- if openerr then
+ if not open_logfile() then
return false
end
-
- logfile, openerr = io.open(logfilename, 'a+')
- if not logfile then
- local err_msg = string.format('Failed to open LSP client log file: %s', openerr)
- notify(err_msg, vim.log.levels.ERROR)
- return false
+ local info = debug.getinfo(2, 'Sl')
+ local header = string.format(
+ '[%s][%s] ...%s:%s',
+ level,
+ os.date(log_date_format),
+ info.short_src:sub(-16),
+ info.currentline
+ )
+ local parts = { header }
+ for i = 1, argc do
+ local arg = select(i, ...)
+ table.insert(parts, arg == nil and 'nil' or format_func(arg))
end
+ assert(logfile)
+ logfile:write(table.concat(parts, '\t'), '\n')
+ logfile:flush()
+ end
+end
- local log_info = vim.uv.fs_stat(logfilename)
- if log_info and log_info.size > 1e9 then
- local warn_msg = string.format(
- 'LSP client log is large (%d MB): %s',
- log_info.size / (1000 * 1000),
- logfilename
- )
- notify(warn_msg)
- end
+-- If called without arguments, it will check whether the log level is
+-- greater than or equal to this one. When called with arguments, it will
+-- log at that level (if applicable, it is checked either way).
- -- Start message for logging
- logfile:write(string.format('[START][%s] LSP logging initiated\n', os.date(log_date_format)))
- return true
- end
+--- @nodoc
+log.debug = create_logger('DEBUG', vim.log.levels.DEBUG)
- for level, levelnr in pairs(log.levels) do
- -- Also export the log level on the root object.
- log[level] = levelnr
- -- FIXME: DOC
- -- Should be exposed in the vim docs.
- --
- -- Set the lowercase name as the main use function.
- -- If called without arguments, it will check whether the log level is
- -- greater than or equal to this one. When called with arguments, it will
- -- log at that level (if applicable, it is checked either way).
- --
- -- Recommended usage:
- -- ```
- -- if log.warn() then
- -- log.warn("123")
- -- end
- -- ```
- --
- -- This way you can avoid string allocations if the log level isn't high enough.
- if level ~= 'OFF' then
- log[level:lower()] = function(...)
- local argc = select('#', ...)
- if levelnr < current_log_level then
- return false
- end
- if argc == 0 then
- return true
- end
- if not open_logfile() then
- return false
- end
- local info = debug.getinfo(2, 'Sl')
- local header = string.format(
- '[%s][%s] ...%s:%s',
- level,
- os.date(log_date_format),
- string.sub(info.short_src, #info.short_src - 15),
- info.currentline
- )
- local parts = { header }
- for i = 1, argc do
- local arg = select(i, ...)
- if arg == nil then
- table.insert(parts, 'nil')
- else
- table.insert(parts, format_func(arg))
- end
- end
- logfile:write(table.concat(parts, '\t'), '\n')
- logfile:flush()
- end
- end
- end
-end
+--- @nodoc
+log.error = create_logger('ERROR', vim.log.levels.ERROR)
--- This is put here on purpose after the loop above so that it doesn't
--- interfere with iterating the levels
-vim.tbl_add_reverse_lookup(log.levels)
+--- @nodoc
+log.info = create_logger('INFO', vim.log.levels.INFO)
+
+--- @nodoc
+log.trace = create_logger('TRACE', vim.log.levels.TRACE)
+
+--- @nodoc
+log.warn = create_logger('WARN', vim.log.levels.WARN)
--- Sets the current log level.
---@param level (string|integer) One of `vim.lsp.log.levels`
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 660b126ce4..1aacf63392 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -26,24 +26,6 @@ local function format_message_with_content_length(message)
})
end
-local function log_error(...)
- if log.error() then
- log.error(...)
- end
-end
-
-local function log_info(...)
- if log.info() then
- log.info(...)
- end
-end
-
-local function log_debug(...)
- if log.debug() then
- log.debug(...)
- end
-end
-
---@class vim.lsp.rpc.Headers: {string: any}
---@field content_length integer
@@ -65,7 +47,7 @@ local function parse_headers(header)
key = key:lower():gsub('%-', '_') --- @type string
headers[key] = value
else
- log_error('invalid header line %q', line)
+ log.error('invalid header line %q', line)
error(string.format('invalid header line %q', line))
end
end
@@ -224,7 +206,7 @@ local default_dispatchers = {
---@param method string The invoked LSP method
---@param params table Parameters for the invoked LSP method
notification = function(method, params)
- log_debug('notification', method, params)
+ log.debug('notification', method, params)
end,
--- Default dispatcher for requests sent to an LSP server.
@@ -234,7 +216,7 @@ local default_dispatchers = {
---@return any result (always nil for the default dispatchers)
---@return lsp.ResponseError error `vim.lsp.protocol.ErrorCodes.MethodNotFound`
server_request = function(method, params)
- log_debug('server_request', method, params)
+ log.debug('server_request', method, params)
return nil, M.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end,
@@ -243,7 +225,7 @@ local default_dispatchers = {
---@param code integer Exit code
---@param signal integer Number describing the signal used to terminate (if any)
on_exit = function(code, signal)
- log_info('client_exit', { code = code, signal = signal })
+ log.info('client_exit', { code = code, signal = signal })
end,
--- Default dispatcher for client errors.
@@ -251,7 +233,7 @@ local default_dispatchers = {
---@param code integer Error code
---@param err any Details about the error
on_error = function(code, err)
- log_error('client_error:', M.client_errors[code], err)
+ log.error('client_error:', M.client_errors[code], err)
end,
}
@@ -297,7 +279,7 @@ local Client = {}
---@private
function Client:encode_and_send(payload)
- log_debug('rpc.send', payload)
+ log.debug('rpc.send', payload)
if self.transport.is_closing() then
return false
end
@@ -419,7 +401,7 @@ function Client:handle_body(body)
self:on_error(M.client_errors.INVALID_SERVER_JSON, decoded)
return
end
- log_debug('rpc.receive', decoded)
+ log.debug('rpc.receive', decoded)
if type(decoded.method) == 'string' and decoded.id then
local err --- @type lsp.ResponseError|nil
@@ -434,7 +416,7 @@ function Client:handle_body(body)
decoded.method,
decoded.params
)
- log_debug(
+ log.debug(
'server_request: callback result',
{ status = status, result = result, err = err }
)
@@ -490,7 +472,7 @@ function Client:handle_body(body)
if decoded.error then
local mute_error = false
if decoded.error.code == protocol.ErrorCodes.RequestCancelled then
- log_debug('Received cancellation ack', decoded)
+ log.debug('Received cancellation ack', decoded)
mute_error = true
end
@@ -526,7 +508,7 @@ function Client:handle_body(body)
)
else
self:on_error(M.client_errors.NO_RESULT_CALLBACK_FOUND, decoded)
- log_error('No callback found for server response id ' .. result_id)
+ log.error('No callback found for server response id ' .. result_id)
end
elseif type(decoded.method) == 'string' then
-- Notification
@@ -773,7 +755,7 @@ end
--- - `is_closing()` returns a boolean indicating if the RPC is closing.
--- - `terminate()` terminates the RPC client.
function M.start(cmd, cmd_args, dispatchers, extra_spawn_params)
- log_info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params })
+ log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params })
validate({
cmd = { cmd, 's' },
@@ -813,7 +795,7 @@ function M.start(cmd, cmd_args, dispatchers, extra_spawn_params)
local stderr_handler = function(_, chunk)
if chunk then
- log_error('rpc', cmd, 'stderr', chunk)
+ log.error('rpc', cmd, 'stderr', chunk)
end
end