aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria José Solano <majosolano99@gmail.com>2024-12-04 05:14:47 -0800
committerGitHub <noreply@github.com>2024-12-04 05:14:47 -0800
commite56437cd48f7df87ccdfb79812ee56241c0da0cb (patch)
tree95ace99b60a4b237f714c17717788a1e08d18247
parentb079a9d2e76062ee7275e35a4623108550e836a5 (diff)
downloadrneovim-e56437cd48f7df87ccdfb79812ee56241c0da0cb.tar.gz
rneovim-e56437cd48f7df87ccdfb79812ee56241c0da0cb.tar.bz2
rneovim-e56437cd48f7df87ccdfb79812ee56241c0da0cb.zip
feat(lsp): deprecate vim.lsp.start_client #31341
Problem: LSP module has multiple "start" interfaces. Solution: - Enhance vim.lsp.start - Deprecate vim.lsp.start_client
-rw-r--r--runtime/doc/deprecated.txt1
-rw-r--r--runtime/doc/lsp.txt36
-rw-r--r--runtime/lua/vim/lsp.lua208
-rw-r--r--runtime/lua/vim/lsp/client.lua8
-rw-r--r--runtime/lua/vim/lsp/rpc.lua2
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua4
-rw-r--r--test/functional/plugin/lsp/semantic_tokens_spec.lua2
-rw-r--r--test/functional/plugin/lsp_spec.lua4
8 files changed, 139 insertions, 126 deletions
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index c6ca5e5ce9..ab9c0b2ce8 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -64,6 +64,7 @@ LSP
• `client.is_stopped()` Use |Client:is_stopped()| instead.
• `client.supports_method()` Use |Client:supports_method()| instead.
• `client.on_attach()` Use |Client:on_attach()| instead.
+• `vim.lsp.start_client()` Use |vim.lsp.start()| instead.
------------------------------------------------------------------------------
DEPRECATED IN 0.10 *deprecated-0.10*
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index e311831bd3..2654d7f14f 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -841,12 +841,11 @@ start({config}, {opts}) *vim.lsp.start()*
})
<
- See |vim.lsp.start_client()| for all available options. The most important
+ See |vim.lsp.ClientConfig| for all available options. The most important
are:
• `name` arbitrary name for the LSP client. Should be unique per language
server.
- • `cmd` command string[] or function, described at
- |vim.lsp.start_client()|.
+ • `cmd` command string[] or function.
• `root_dir` path to the project root. By default this is used to decide
if an existing client should be re-used. The example above uses
|vim.fs.root()| to detect the root by traversing the file system upwards
@@ -868,7 +867,7 @@ start({config}, {opts}) *vim.lsp.start()*
Parameters: ~
• {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
|vim.lsp.ClientConfig|.
- • {opts} (`table?`) Optional keyword arguments
+ • {opts} (`table?`) Optional keyword arguments.
• {reuse_client}?
(`fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): boolean`)
Predicate used to decide if a client should be re-used.
@@ -876,25 +875,15 @@ start({config}, {opts}) *vim.lsp.start()*
re-uses a client if name and root_dir matches.
• {bufnr}? (`integer`) Buffer handle to attach to if
starting or re-using a client (0 for current).
+ • {attach}? (`boolean`) Whether to attach the client to a
+ buffer (default true). If set to `false`, `reuse_client`
+ and `bufnr` will be ignored.
• {silent}? (`boolean`) Suppress error reporting if the LSP
server fails to start (default false).
Return: ~
(`integer?`) client_id
-start_client({config}) *vim.lsp.start_client()*
- Starts and initializes a client with the given configuration.
-
- Parameters: ~
- • {config} (`vim.lsp.ClientConfig`) Configuration for the server. See
- |vim.lsp.ClientConfig|.
-
- Return (multiple): ~
- (`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
- client has been initialized.
- (`string?`) Error message, if any
-
status() *vim.lsp.status()*
Consumes the latest progress messages from all clients and formats them as
a string. Empty if there are no clients or if no new messages
@@ -968,8 +957,7 @@ Lua module: vim.lsp.client *lsp-client*
server.
• {config} (`vim.lsp.ClientConfig`) copy of the table
that was passed by the user to
- |vim.lsp.start_client()|. See
- |vim.lsp.ClientConfig|.
+ |vim.lsp.start()|. See |vim.lsp.ClientConfig|.
• {server_capabilities} (`lsp.ServerCapabilities?`) Response from the
server sent on `initialize` describing the
server's capabilities.
@@ -1093,7 +1081,7 @@ Lua module: vim.lsp.client *lsp-client*
• {commands}? (`table<string,fun(command: lsp.Command, ctx: table)>`)
Table that maps string of clientside commands to
user-defined functions. Commands passed to
- start_client take precedence over the global
+ `start()` take precedence over the global
command registry. Each key must be a unique
command name, and the value is a function which
is called if any LSP action (code action, code
@@ -1122,9 +1110,9 @@ Lua module: vim.lsp.client *lsp-client*
Callback invoked before the LSP "initialize"
phase, where `params` contains the parameters
being sent to the server and `config` is the
- config that was passed to
- |vim.lsp.start_client()|. You can use this to
- modify parameters before they are sent.
+ config that was passed to |vim.lsp.start()|. You
+ can use this to modify parameters before they
+ are sent.
• {on_init}? (`elem_or_list<fun(client: vim.lsp.Client, initialize_result: lsp.InitializeResult)>`)
Callback invoked after LSP "initialize", where
`result` is a table of `capabilities` and
@@ -2296,7 +2284,7 @@ connect({host_or_path}, {port}) *vim.lsp.rpc.connect()*
• a host and port via TCP
Return a function that can be passed to the `cmd` field for
- |vim.lsp.start_client()| or |vim.lsp.start()|.
+ |vim.lsp.start()|.
Parameters: ~
• {host_or_path} (`string`) host to connect to or path to a pipe/domain
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index b1a3316e3e..4717d7995a 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -211,17 +211,117 @@ local function reuse_client_default(client, config)
return false
end
+--- Reset defaults set by `set_defaults`.
+--- Must only be called if the last client attached to a buffer exits.
+local function reset_defaults(bufnr)
+ if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
+ vim.bo[bufnr].tagfunc = nil
+ end
+ if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
+ vim.bo[bufnr].omnifunc = nil
+ end
+ if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
+ vim.bo[bufnr].formatexpr = nil
+ end
+ vim._with({ buf = bufnr }, function()
+ local keymap = vim.fn.maparg('K', 'n', false, true)
+ if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
+ vim.keymap.del('n', 'K', { buffer = bufnr })
+ end
+ end)
+end
+
+--- @param code integer
+--- @param signal integer
+--- @param client_id integer
+local function on_client_exit(code, signal, client_id)
+ local client = all_clients[client_id]
+
+ vim.schedule(function()
+ for bufnr in pairs(client.attached_buffers) do
+ if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
+ api.nvim_exec_autocmds('LspDetach', {
+ buffer = bufnr,
+ modeline = false,
+ data = { client_id = client_id },
+ })
+ end
+
+ client.attached_buffers[bufnr] = nil
+
+ if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
+ reset_defaults(bufnr)
+ end
+ end
+
+ local namespace = vim.lsp.diagnostic.get_namespace(client_id)
+ vim.diagnostic.reset(namespace)
+ end)
+
+ local name = client.name or 'unknown'
+
+ -- Schedule the deletion of the client object so that it exists in the execution of LspDetach
+ -- autocommands
+ vim.schedule(function()
+ all_clients[client_id] = nil
+
+ -- Client can be absent if executable starts, but initialize fails
+ -- init/attach won't have happened
+ if client then
+ changetracking.reset(client)
+ end
+ if code ~= 0 or (signal ~= 0 and signal ~= 15) then
+ local msg = string.format(
+ 'Client %s quit with exit code %s and signal %s. Check log for errors: %s',
+ name,
+ code,
+ signal,
+ lsp.get_log_path()
+ )
+ vim.notify(msg, vim.log.levels.WARN)
+ end
+ end)
+end
+
+--- Creates and initializes a client with the given configuration.
+--- @param config vim.lsp.ClientConfig Configuration for the server.
+--- @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
+--- the client has been initialized.
+--- @return string? # Error message, if any
+local function create_and_initialize_client(config)
+ local ok, res = pcall(require('vim.lsp.client').create, config)
+ if not ok then
+ return nil, res --[[@as string]]
+ end
+
+ local client = assert(res)
+
+ --- @diagnostic disable-next-line: invisible
+ table.insert(client._on_exit_cbs, on_client_exit)
+
+ all_clients[client.id] = client
+
+ client:initialize()
+
+ return client.id, nil
+end
+
--- @class vim.lsp.start.Opts
--- @inlinedoc
---
--- 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
--- root_dir matches.
---- @field reuse_client? fun(client: vim.lsp.Client, config: vim.lsp.ClientConfig): 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).
--- @field bufnr? integer
---
+--- Whether to attach the client to a buffer (default true).
+--- If set to `false`, `reuse_client` and `bufnr` will be ignored.
+--- @field attach? boolean
+---
--- Suppress error reporting if the LSP server fails to start (default false).
--- @field silent? boolean
@@ -239,10 +339,10 @@ end
--- })
--- ```
---
---- See |vim.lsp.start_client()| for all available options. The most important are:
+--- See |vim.lsp.ClientConfig| for all available options. The most important are:
---
--- - `name` arbitrary name for the LSP client. Should be unique per language server.
---- - `cmd` command string[] or function, described at |vim.lsp.start_client()|.
+--- - `cmd` command string[] or function.
--- - `root_dir` path to the project root. By default this is used to decide if an existing client
--- should be re-used. The example above uses |vim.fs.root()| to detect the root by traversing
--- the file system upwards starting from the current directory until either a `pyproject.toml`
@@ -262,7 +362,7 @@ end
--- `ftplugin/<filetype_name>.lua` (See |ftplugin-name|)
---
--- @param config vim.lsp.ClientConfig Configuration for the server.
---- @param opts vim.lsp.start.Opts? Optional keyword arguments
+--- @param opts vim.lsp.start.Opts? Optional keyword arguments.
--- @return integer? client_id
function lsp.start(config, opts)
opts = opts or {}
@@ -271,6 +371,10 @@ function lsp.start(config, opts)
for _, client in pairs(all_clients) do
if reuse_client(client, config) then
+ if opts.attach == false then
+ return client.id
+ end
+
if lsp.buf_attach_client(bufnr, client.id) then
return client.id
else
@@ -279,7 +383,7 @@ function lsp.start(config, opts)
end
end
- local client_id, err = lsp.start_client(config)
+ local client_id, err = create_and_initialize_client(config)
if err then
if not opts.silent then
vim.notify(err, vim.log.levels.WARN)
@@ -287,6 +391,10 @@ function lsp.start(config, opts)
return nil
end
+ if opts.attach == false then
+ return client_id
+ end
+
if client_id and lsp.buf_attach_client(bufnr, client_id) then
return client_id
end
@@ -383,78 +491,7 @@ function lsp._set_defaults(client, bufnr)
end
end
---- Reset defaults set by `set_defaults`.
---- Must only be called if the last client attached to a buffer exits.
-local function reset_defaults(bufnr)
- if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
- vim.bo[bufnr].tagfunc = nil
- end
- if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
- vim.bo[bufnr].omnifunc = nil
- end
- if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then
- vim.bo[bufnr].formatexpr = nil
- end
- vim._with({ buf = bufnr }, function()
- local keymap = vim.fn.maparg('K', 'n', false, true)
- if keymap and keymap.callback == vim.lsp.buf.hover and keymap.buffer == 1 then
- vim.keymap.del('n', 'K', { buffer = bufnr })
- end
- end)
-end
-
---- @param code integer
---- @param signal integer
---- @param client_id integer
-local function on_client_exit(code, signal, client_id)
- local client = all_clients[client_id]
-
- vim.schedule(function()
- for bufnr in pairs(client.attached_buffers) do
- if client and client.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then
- api.nvim_exec_autocmds('LspDetach', {
- buffer = bufnr,
- modeline = false,
- data = { client_id = client_id },
- })
- end
-
- client.attached_buffers[bufnr] = nil
-
- if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then
- reset_defaults(bufnr)
- end
- end
-
- local namespace = vim.lsp.diagnostic.get_namespace(client_id)
- vim.diagnostic.reset(namespace)
- end)
-
- local name = client.name or 'unknown'
-
- -- Schedule the deletion of the client object so that it exists in the execution of LspDetach
- -- autocommands
- vim.schedule(function()
- all_clients[client_id] = nil
-
- -- Client can be absent if executable starts, but initialize fails
- -- init/attach won't have happened
- if client then
- changetracking.reset(client)
- end
- if code ~= 0 or (signal ~= 0 and signal ~= 15) then
- local msg = string.format(
- 'Client %s quit with exit code %s and signal %s. Check log for errors: %s',
- name,
- code,
- signal,
- lsp.get_log_path()
- )
- vim.notify(msg, vim.log.levels.WARN)
- end
- end)
-end
-
+--- @deprecated
--- Starts and initializes a client with the given configuration.
--- @param config vim.lsp.ClientConfig Configuration for the server.
--- @return integer? client_id |vim.lsp.get_client_by_id()| Note: client may not be
@@ -462,21 +499,8 @@ end
--- the client has been initialized.
--- @return string? # Error message, if any
function lsp.start_client(config)
- local ok, res = pcall(require('vim.lsp.client').create, config)
- if not ok then
- return nil, res --[[@as string]]
- end
-
- local client = assert(res)
-
- --- @diagnostic disable-next-line: invisible
- table.insert(client._on_exit_cbs, on_client_exit)
-
- all_clients[client.id] = client
-
- client:initialize()
-
- return client.id, nil
+ vim.deprecate('vim.lsp.start_client()', 'vim.lsp.start()', '0.13')
+ return create_and_initialize_client(config)
end
---Buffer lifecycle handler for textDocument/didSave
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index a14b6ccda6..a83d75bf75 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -78,7 +78,7 @@ local validate = vim.validate
--- @field settings? table
---
--- Table that maps string of clientside commands to user-defined functions.
---- Commands passed to start_client take precedence over the global command registry. Each key
+--- Commands passed to `start()` take precedence over the global command registry. Each key
--- must be a unique command name, and the value is a function which is called if any LSP action
--- (code action, code lenses, ...) triggers the command.
--- @field commands? table<string,fun(command: lsp.Command, ctx: table)>
@@ -104,7 +104,7 @@ local validate = vim.validate
--- @field on_error? fun(code: integer, err: string)
---
--- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters
---- being sent to the server and `config` is the config that was passed to |vim.lsp.start_client()|.
+--- being sent to the server and `config` is the config that was passed to |vim.lsp.start()|.
--- You can use this to modify parameters before they are sent.
--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)
---
@@ -167,7 +167,7 @@ local validate = vim.validate
--- @field requests table<integer,{ type: string, bufnr: integer, method: string}>
---
--- copy of the table that was passed by the user
---- to |vim.lsp.start_client()|.
+--- to |vim.lsp.start()|.
--- @field config vim.lsp.ClientConfig
---
--- Response from the server sent on `initialize` describing the server's
@@ -307,7 +307,7 @@ local function default_get_language_id(_bufnr, filetype)
return filetype
end
---- Validates a client configuration as given to |vim.lsp.start_client()|.
+--- Validates a client configuration as given to |vim.lsp.start()|.
--- @param config vim.lsp.ClientConfig
local function validate_config(config)
validate('config', config, 'table')
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 6c8564845f..2327a37ab1 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -617,7 +617,7 @@ end
--- - a host and port via TCP
---
--- Return a function that can be passed to the `cmd` field for
---- |vim.lsp.start_client()| or |vim.lsp.start()|.
+--- |vim.lsp.start()|.
---
---@param host_or_path string host to connect to or path to a pipe/domain socket
---@param port integer? TCP port to connect to. If absent the first argument must be a pipe
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index ca9196562c..4ecb056d01 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -89,7 +89,7 @@ describe('vim.lsp.diagnostic', function()
return extmarks
end
- client_id = assert(vim.lsp.start_client {
+ client_id = assert(vim.lsp.start({
cmd_env = {
NVIM_LUA_NOTRACK = '1',
},
@@ -101,7 +101,7 @@ describe('vim.lsp.diagnostic', function()
'--headless',
},
offset_encoding = 'utf-16',
- })
+ }, { attach = false }))
end)
fake_uri = 'file:///fake/uri'
diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua
index 280bd27207..9912bf2063 100644
--- a/test/functional/plugin/lsp/semantic_tokens_spec.lua
+++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua
@@ -456,7 +456,7 @@ describe('semantic token highlighting', function()
vim.notify = function(...)
table.insert(_G.notifications, 1, { ... })
end
- return vim.lsp.start_client({ name = 'dummy', cmd = _G.server.cmd })
+ return vim.lsp.start({ name = 'dummy', cmd = _G.server.cmd }, { attach = false })
end)
eq(false, exec_lua('return vim.lsp.buf_is_attached(0, ...)', client_id))
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index e30d1ba411..e735e20ff5 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -95,7 +95,7 @@ describe('LSP', function()
exec_lua(function()
_G.lsp = require('vim.lsp')
function _G.test__start_client()
- return vim.lsp.start_client {
+ return vim.lsp.start({
cmd_env = {
NVIM_LOG_FILE = fake_lsp_logfile,
NVIM_APPNAME = 'nvim_lsp_test',
@@ -112,7 +112,7 @@ describe('LSP', function()
name = 'test_folder',
},
},
- }
+ }, { attach = false })
end
_G.TEST_CLIENT1 = _G.test__start_client()
end)