mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
fix(lsp): add "silent" option to vim.lsp.start (#28478)
vim.notify cannot be suppressed and it is not always necessary to display a visible warning to the user if the RPC process fails to start. For instance, a user may have the same LSP configuration across systems, some of which may not have all of the LSP server executables installed. In that case, the user receives a notification every time a file is opened that they cannot suppress. Instead of using vim.notify in vim.lsp.rpc, propagate a normal error up through the call stack and use vim.notify in vim.lsp.start() only if the "silent" option is not set. This also updates lsp.start_client() to return an error message as its second return value if an error occurred, rather than calling vim.notify directly. Callers of lsp.start_client() will need to update call sites appropriately if they wish to report errors to the user (or even better, switch to vim.lsp.start).
This commit is contained in:
@@ -869,12 +869,14 @@ start({config}, {opts}) *vim.lsp.start()*
|
|||||||
|vim.lsp.ClientConfig|.
|
|vim.lsp.ClientConfig|.
|
||||||
• {opts} (`table?`) Optional keyword arguments
|
• {opts} (`table?`) Optional keyword arguments
|
||||||
• {reuse_client}
|
• {reuse_client}
|
||||||
(`fun(client: vim.lsp.Client, config: table): boolean`)
|
(`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
|
||||||
Predicate used to decide if a client should be re-used.
|
Predicate used to decide if a client should be re-used.
|
||||||
Used on all running clients. The default implementation
|
Used on all running clients. The default implementation
|
||||||
re-uses a client if name and root_dir matches.
|
re-uses a client if name and root_dir matches.
|
||||||
• {bufnr} (`integer`) Buffer handle to attach to if starting
|
• {bufnr} (`integer`) Buffer handle to attach to if starting
|
||||||
or re-using a client (0 for current).
|
or re-using a client (0 for current).
|
||||||
|
• {silent} (`boolean`) Suppress error reporting if the LSP
|
||||||
|
server fails to start (default false).
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
(`integer?`) client_id
|
(`integer?`) client_id
|
||||||
@@ -886,10 +888,11 @@ start_client({config}) *vim.lsp.start_client()*
|
|||||||
• {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
|
• {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
|
||||||
|vim.lsp.ClientConfig|.
|
|vim.lsp.ClientConfig|.
|
||||||
|
|
||||||
Return: ~
|
Return (multiple): ~
|
||||||
(`integer?`) client_id |vim.lsp.get_client_by_id()| Note: client may
|
(`integer?`) client_id |vim.lsp.get_client_by_id()| Note: client may
|
||||||
not be fully initialized. Use `on_init` to do any actions once the
|
not be fully initialized. Use `on_init` to do any actions once the
|
||||||
client has been initialized.
|
client has been initialized.
|
||||||
|
(`string?`) Error message, if any
|
||||||
|
|
||||||
status() *vim.lsp.status()*
|
status() *vim.lsp.status()*
|
||||||
Consumes the latest progress messages from all clients and formats them as
|
Consumes the latest progress messages from all clients and formats them as
|
||||||
@@ -1073,7 +1076,7 @@ Lua module: vim.lsp.client *lsp-client*
|
|||||||
*vim.lsp.ClientConfig*
|
*vim.lsp.ClientConfig*
|
||||||
|
|
||||||
Fields: ~
|
Fields: ~
|
||||||
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient?`)
|
• {cmd} (`string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient`)
|
||||||
command string[] that launches the language
|
command string[] that launches the language
|
||||||
server (treated as in |jobstart()|, must be
|
server (treated as in |jobstart()|, must be
|
||||||
absolute or on `$PATH`, shell constructs like
|
absolute or on `$PATH`, shell constructs like
|
||||||
@@ -2340,7 +2343,7 @@ start({cmd}, {dispatchers}, {extra_spawn_params}) *vim.lsp.rpc.start()*
|
|||||||
See |vim.system()|
|
See |vim.system()|
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
(`vim.lsp.rpc.PublicClient?`) Client RPC object, with these methods:
|
(`vim.lsp.rpc.PublicClient`) Client RPC object, with these methods:
|
||||||
• `notify()` |vim.lsp.rpc.notify()|
|
• `notify()` |vim.lsp.rpc.notify()|
|
||||||
• `request()` |vim.lsp.rpc.request()|
|
• `request()` |vim.lsp.rpc.request()|
|
||||||
• `is_closing()` returns a boolean indicating if the RPC is closing.
|
• `is_closing()` returns a boolean indicating if the RPC is closing.
|
||||||
|
@@ -243,6 +243,8 @@ The following new APIs and features were added.
|
|||||||
(e.g. `commitCharacters`). Note that this might affect plugins and
|
(e.g. `commitCharacters`). Note that this might affect plugins and
|
||||||
language servers that don't support the feature, and in such cases the
|
language servers that don't support the feature, and in such cases the
|
||||||
respective capability can be unset.
|
respective capability can be unset.
|
||||||
|
• |vim.lsp.start()| accepts a "silent" option for suppressing messages
|
||||||
|
if an LSP server failed to start.
|
||||||
|
|
||||||
• Treesitter
|
• Treesitter
|
||||||
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and
|
• Bundled parsers and queries (highlight, folds) for Markdown, Python, and
|
||||||
|
@@ -195,10 +195,13 @@ end
|
|||||||
--- Predicate used to decide if a client should be re-used. Used on all
|
--- Predicate used to decide if a client should be re-used. Used on all
|
||||||
--- running clients. The default implementation re-uses a client if name and
|
--- running clients. The default implementation re-uses a client if name and
|
||||||
--- root_dir matches.
|
--- root_dir matches.
|
||||||
--- @field reuse_client fun(client: vim.lsp.Client, config: table): boolean
|
--- @field reuse_client fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean
|
||||||
---
|
---
|
||||||
--- Buffer handle to attach to if starting or re-using a client (0 for current).
|
--- Buffer handle to attach to if starting or re-using a client (0 for current).
|
||||||
--- @field bufnr integer
|
--- @field bufnr integer
|
||||||
|
---
|
||||||
|
--- Suppress error reporting if the LSP server fails to start (default false).
|
||||||
|
--- @field silent boolean
|
||||||
|
|
||||||
--- Create a new LSP client and start a language server or reuses an already
|
--- Create a new LSP client and start a language server or reuses an already
|
||||||
--- running client if one is found matching `name` and `root_dir`.
|
--- running client if one is found matching `name` and `root_dir`.
|
||||||
@@ -246,19 +249,25 @@ function lsp.start(config, opts)
|
|||||||
|
|
||||||
for _, client in pairs(all_clients) do
|
for _, client in pairs(all_clients) do
|
||||||
if reuse_client(client, config) then
|
if reuse_client(client, config) then
|
||||||
lsp.buf_attach_client(bufnr, client.id)
|
if lsp.buf_attach_client(bufnr, client.id) then
|
||||||
return client.id
|
return client.id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local client_id = lsp.start_client(config)
|
local client_id, err = lsp.start_client(config)
|
||||||
|
if err then
|
||||||
if not client_id then
|
if not opts.silent then
|
||||||
return -- lsp.start_client will have printed an error
|
vim.notify(err, vim.log.levels.WARN)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
lsp.buf_attach_client(bufnr, client_id)
|
if client_id and lsp.buf_attach_client(bufnr, client_id) then
|
||||||
return client_id
|
return client_id
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Consumes the latest progress messages from all clients and formats them as a string.
|
--- Consumes the latest progress messages from all clients and formats them as a string.
|
||||||
@@ -420,16 +429,18 @@ end
|
|||||||
|
|
||||||
--- Starts and initializes a client with the given configuration.
|
--- Starts and initializes a client with the given configuration.
|
||||||
--- @param config vim.lsp.ClientConfig Configuration for the server.
|
--- @param config vim.lsp.ClientConfig Configuration for the server.
|
||||||
--- @return integer|nil client_id |vim.lsp.get_client_by_id()| Note: client may not be
|
--- @return integer? client_id |vim.lsp.get_client_by_id()| Note: client may not be
|
||||||
--- fully initialized. Use `on_init` to do any actions once
|
--- fully initialized. Use `on_init` to do any actions once
|
||||||
--- the client has been initialized.
|
--- the client has been initialized.
|
||||||
|
--- @return string? # Error message, if any
|
||||||
function lsp.start_client(config)
|
function lsp.start_client(config)
|
||||||
local client = require('vim.lsp.client').create(config)
|
local ok, res = pcall(require('vim.lsp.client').create, config)
|
||||||
|
if not ok then
|
||||||
if not client then
|
return nil, res --[[@as string]]
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local client = assert(res)
|
||||||
|
|
||||||
--- @diagnostic disable-next-line: invisible
|
--- @diagnostic disable-next-line: invisible
|
||||||
table.insert(client._on_exit_cbs, on_client_exit)
|
table.insert(client._on_exit_cbs, on_client_exit)
|
||||||
|
|
||||||
@@ -437,7 +448,7 @@ function lsp.start_client(config)
|
|||||||
|
|
||||||
client:initialize()
|
client:initialize()
|
||||||
|
|
||||||
return client.id
|
return client.id, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Notify all attached clients that a buffer has changed.
|
--- Notify all attached clients that a buffer has changed.
|
||||||
|
@@ -37,7 +37,7 @@ local validate = vim.validate
|
|||||||
--- `is_closing` and `terminate`.
|
--- `is_closing` and `terminate`.
|
||||||
--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
|
--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
|
||||||
--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
|
--- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()|
|
||||||
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient?
|
--- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers): vim.lsp.rpc.PublicClient
|
||||||
---
|
---
|
||||||
--- Directory to launch the `cmd` process. Not related to `root_dir`.
|
--- Directory to launch the `cmd` process. Not related to `root_dir`.
|
||||||
--- (default: cwd)
|
--- (default: cwd)
|
||||||
@@ -506,25 +506,17 @@ function Client.create(config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
-- Start the RPC client.
|
-- Start the RPC client.
|
||||||
local rpc --- @type vim.lsp.rpc.PublicClient?
|
|
||||||
local config_cmd = config.cmd
|
local config_cmd = config.cmd
|
||||||
if type(config_cmd) == 'function' then
|
if type(config_cmd) == 'function' then
|
||||||
rpc = config_cmd(dispatchers)
|
self.rpc = config_cmd(dispatchers)
|
||||||
else
|
else
|
||||||
rpc = lsp.rpc.start(config_cmd, dispatchers, {
|
self.rpc = lsp.rpc.start(config_cmd, dispatchers, {
|
||||||
cwd = config.cmd_cwd,
|
cwd = config.cmd_cwd,
|
||||||
env = config.cmd_env,
|
env = config.cmd_env,
|
||||||
detached = config.detached,
|
detached = config.detached,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Return nil if the rpc client fails to start
|
|
||||||
if not rpc then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
self.rpc = rpc
|
|
||||||
|
|
||||||
setmetatable(self, Client)
|
setmetatable(self, Client)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
@@ -722,7 +722,7 @@ end
|
|||||||
--- @param cmd string[] Command to start the LSP server.
|
--- @param cmd string[] Command to start the LSP server.
|
||||||
--- @param dispatchers? vim.lsp.rpc.Dispatchers
|
--- @param dispatchers? vim.lsp.rpc.Dispatchers
|
||||||
--- @param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams
|
--- @param extra_spawn_params? vim.lsp.rpc.ExtraSpawnParams
|
||||||
--- @return vim.lsp.rpc.PublicClient? : Client RPC object, with these methods:
|
--- @return vim.lsp.rpc.PublicClient : Client RPC object, with these methods:
|
||||||
--- - `notify()` |vim.lsp.rpc.notify()|
|
--- - `notify()` |vim.lsp.rpc.notify()|
|
||||||
--- - `request()` |vim.lsp.rpc.request()|
|
--- - `request()` |vim.lsp.rpc.request()|
|
||||||
--- - `is_closing()` returns a boolean indicating if the RPC is closing.
|
--- - `is_closing()` returns a boolean indicating if the RPC is closing.
|
||||||
@@ -797,8 +797,7 @@ function M.start(cmd, dispatchers, extra_spawn_params)
|
|||||||
end
|
end
|
||||||
local msg =
|
local msg =
|
||||||
string.format('Spawning language server with cmd: `%s` failed%s', vim.inspect(cmd), sfx)
|
string.format('Spawning language server with cmd: `%s` failed%s', vim.inspect(cmd), sfx)
|
||||||
vim.notify(msg, vim.log.levels.WARN)
|
error(msg)
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
sysobj = sysobj_or_err --[[@as vim.SystemObj]]
|
sysobj = sysobj_or_err --[[@as vim.SystemObj]]
|
||||||
|
Reference in New Issue
Block a user