aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/client.lua
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-05-24 19:18:11 +0000
committerJosh Rahm <joshuarahm@gmail.com>2024-05-24 19:18:11 +0000
commitff7ed8f586589d620a806c3758fac4a47a8e7e15 (patch)
tree729bbcb92231538fa61dab6c3d890b025484b7f5 /runtime/lua/vim/lsp/client.lua
parent376914f419eb08fdf4c1a63a77e1f035898a0f10 (diff)
parent28c04948a1c887a1cc0cb64de79fa32631700466 (diff)
downloadrneovim-ff7ed8f586589d620a806c3758fac4a47a8e7e15.tar.gz
rneovim-ff7ed8f586589d620a806c3758fac4a47a8e7e15.tar.bz2
rneovim-ff7ed8f586589d620a806c3758fac4a47a8e7e15.zip
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'runtime/lua/vim/lsp/client.lua')
-rw-r--r--runtime/lua/vim/lsp/client.lua95
1 files changed, 72 insertions, 23 deletions
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
index ff0db166d5..4beb7fefda 100644
--- a/runtime/lua/vim/lsp/client.lua
+++ b/runtime/lua/vim/lsp/client.lua
@@ -15,7 +15,7 @@ local validate = vim.validate
--- @inlinedoc
---
--- Allow using incremental sync for buffer edits
---- (defailt: `true`)
+--- (default: `true`)
--- @field allow_incremental_sync? boolean
---
--- Debounce `didChange` notifications to the server by the given number in milliseconds.
@@ -37,7 +37,7 @@ local validate = vim.validate
--- `is_closing` and `terminate`.
--- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|.
--- 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`.
--- (default: cwd)
@@ -185,6 +185,10 @@ local validate = vim.validate
--- @field root_dir string
---
--- @field attached_buffers table<integer,true>
+---
+--- Buffers that should be attached to upon initialize()
+--- @field package _buffers_to_attach table<integer,true>
+---
--- @field private _log_prefix string
---
--- Track this so that we can escalate automatically if we've already tried a
@@ -225,7 +229,7 @@ local validate = vim.validate
--- If {status} is `true`, the function returns {request_id} as the second
--- result. You can use this with `client.cancel_request(request_id)` to cancel
--- the request.
---- @field request fun(method: string, params: table?, handler: lsp.Handler?, bufnr: integer): boolean, integer?
+--- @field request fun(method: string, params: table?, handler: lsp.Handler?, bufnr: integer?): boolean, integer?
---
--- Sends a request to the server and synchronously waits for the response.
--- This is a wrapper around {client.request}
@@ -416,7 +420,7 @@ local function get_workspace_folders(workspace_folders, root_dir)
return {
{
uri = vim.uri_from_fname(root_dir),
- name = string.format('%s', root_dir),
+ name = root_dir,
},
}
end
@@ -502,25 +506,17 @@ function Client.create(config)
}
-- Start the RPC client.
- local rpc --- @type vim.lsp.rpc.PublicClient?
local config_cmd = config.cmd
if type(config_cmd) == 'function' then
- rpc = config_cmd(dispatchers)
+ self.rpc = config_cmd(dispatchers)
else
- rpc = lsp.rpc.start(config_cmd, dispatchers, {
+ self.rpc = lsp.rpc.start(config_cmd, dispatchers, {
cwd = config.cmd_cwd,
env = config.cmd_env,
detached = config.detached,
})
end
- -- Return nil if the rpc client fails to start
- if not rpc then
- return
- end
-
- self.rpc = rpc
-
setmetatable(self, Client)
return self
@@ -575,6 +571,7 @@ function Client:initialize()
initializationOptions = config.init_options,
capabilities = self.capabilities,
trace = self._trace,
+ workDoneToken = '1',
}
self:_run_callbacks(
@@ -608,8 +605,19 @@ function Client:initialize()
self:_notify(ms.workspace_didChangeConfiguration, { settings = self.settings })
end
+ -- If server is being restarted, make sure to re-attach to any previously attached buffers.
+ -- Save which buffers before on_init in case new buffers are attached.
+ local reattach_bufs = vim.deepcopy(self.attached_buffers)
+
self:_run_callbacks(self._on_init_cbs, lsp.client_errors.ON_INIT_CALLBACK_ERROR, self, result)
+ for buf in pairs(reattach_bufs) do
+ -- The buffer may have been detached in the on_init callback.
+ if self.attached_buffers[buf] then
+ self:_on_attach(buf)
+ end
+ end
+
log.info(
self._log_prefix,
'server_capabilities',
@@ -647,10 +655,10 @@ end
--- checks for capabilities and handler availability.
---
--- @param method string LSP method name.
---- @param params table|nil LSP request params.
---- @param handler lsp.Handler|nil Response |lsp-handler| for this method.
---- @param bufnr integer Buffer handle (0 for current).
---- @return boolean status, integer|nil request_id {status} is a bool indicating
+--- @param params? table LSP request params.
+--- @param handler? lsp.Handler Response |lsp-handler| for this method.
+--- @param bufnr? integer Buffer handle (0 for current).
+--- @return boolean status, integer? request_id {status} is a bool indicating
--- whether the request was successful. If it is `false`, then it will
--- always be `false` (the client has shutdown). If it was
--- successful, then it will return {request_id} as the
@@ -693,7 +701,7 @@ function Client:_request(method, params, handler, bufnr)
local request = { type = 'pending', bufnr = bufnr, method = method }
self.requests[request_id] = request
api.nvim_exec_autocmds('LspRequest', {
- buffer = bufnr,
+ buffer = api.nvim_buf_is_valid(bufnr) and bufnr or nil,
modeline = false,
data = { client_id = self.id, request_id = request_id, request = request },
})
@@ -709,7 +717,7 @@ local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'err
---
--- @param ... string List to write to the buffer
local function err_message(...)
- local message = table.concat(vim.tbl_flatten({ ... }))
+ local message = table.concat(vim.iter({ ... }):flatten():totable())
if vim.in_fast_event() then
vim.schedule(function()
api.nvim_err_writeln(message)
@@ -761,7 +769,7 @@ function Client:_request_sync(method, params, timeout_ms, bufnr)
return request_result
end
---- @private
+--- @package
--- Sends a notification to an LSP server.
---
--- @param method string LSP method name.
@@ -804,7 +812,7 @@ function Client:_cancel_request(id)
if request and request.type == 'pending' then
request.type = 'cancel'
api.nvim_exec_autocmds('LspRequest', {
- buffer = request.bufnr,
+ buffer = api.nvim_buf_is_valid(request.bufnr) and request.bufnr or nil,
modeline = false,
data = { client_id = self.id, request_id = id, request = request },
})
@@ -900,7 +908,7 @@ end
--- @param bufnr integer Number of the buffer, or 0 for current
function Client:_text_document_did_open_handler(bufnr)
changetracking.init(self, bufnr)
- if not vim.tbl_get(self.server_capabilities, 'textDocumentSync', 'openClose') then
+ if not self.supports_method(ms.textDocument_didOpen) then
return
end
if not api.nvim_buf_is_loaded(bufnr) then
@@ -1053,4 +1061,45 @@ function Client:_on_exit(code, signal)
)
end
+--- @package
+--- Add a directory to the workspace folders.
+--- @param dir string?
+function Client:_add_workspace_folder(dir)
+ for _, folder in pairs(self.workspace_folders or {}) do
+ if folder.name == dir then
+ print(dir, 'is already part of this workspace')
+ return
+ end
+ end
+
+ local wf = assert(get_workspace_folders(nil, dir))
+
+ self:_notify(ms.workspace_didChangeWorkspaceFolders, {
+ event = { added = wf, removed = {} },
+ })
+
+ if not self.workspace_folders then
+ self.workspace_folders = {}
+ end
+ vim.list_extend(self.workspace_folders, wf)
+end
+
+--- @package
+--- Remove a directory to the workspace folders.
+--- @param dir string?
+function Client:_remove_workspace_folder(dir)
+ local wf = assert(get_workspace_folders(nil, dir))
+
+ self:_notify(ms.workspace_didChangeWorkspaceFolders, {
+ event = { added = {}, removed = wf },
+ })
+
+ for idx, folder in pairs(self.workspace_folders) do
+ if folder.name == dir then
+ table.remove(self.workspace_folders, idx)
+ break
+ end
+ end
+end
+
return Client