mirror of
https://github.com/neovim/neovim.git
synced 2026-04-21 14:55:33 +00:00
fix(lsp): send didOpen on save to all clients+groups #37454
Problem: _get_and_set_name edits the name for the whole group,
thus only one client per group gets the didOpen message.
Solution: move the logic to _changetracking and loop over every
client per group.
(cherry picked from commit 37eb1b9979)
This commit is contained in:
committed by
github-actions[bot]
parent
3d1c0c9902
commit
fe09c71c34
@@ -883,42 +883,7 @@ end
|
||||
---Buffer lifecycle handler for textDocument/didSave
|
||||
--- @param bufnr integer
|
||||
local function text_document_did_save_handler(bufnr)
|
||||
bufnr = vim._resolve_bufnr(bufnr)
|
||||
local uri = vim.uri_from_bufnr(bufnr)
|
||||
local text = vim.func._memoize('concat', lsp._buf_get_full_text)
|
||||
for _, client in ipairs(lsp.get_clients({ bufnr = bufnr })) do
|
||||
local name = api.nvim_buf_get_name(bufnr)
|
||||
local old_name = changetracking._get_and_set_name(client, bufnr, name)
|
||||
if old_name and name ~= old_name then
|
||||
client:notify('textDocument/didClose', {
|
||||
textDocument = {
|
||||
uri = vim.uri_from_fname(old_name),
|
||||
},
|
||||
})
|
||||
client:notify('textDocument/didOpen', {
|
||||
textDocument = {
|
||||
version = 0,
|
||||
uri = uri,
|
||||
languageId = client.get_language_id(bufnr, vim.bo[bufnr].filetype),
|
||||
text = lsp._buf_get_full_text(bufnr),
|
||||
},
|
||||
})
|
||||
util.buf_versions[bufnr] = 0
|
||||
end
|
||||
local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save')
|
||||
if save_capability then
|
||||
local included_text --- @type string?
|
||||
if type(save_capability) == 'table' and save_capability.includeText then
|
||||
included_text = text(bufnr)
|
||||
end
|
||||
client:notify('textDocument/didSave', {
|
||||
textDocument = {
|
||||
uri = uri,
|
||||
},
|
||||
text = included_text,
|
||||
})
|
||||
end
|
||||
end
|
||||
changetracking._send_did_save(bufnr)
|
||||
end
|
||||
|
||||
--- @type table<integer,true>
|
||||
|
||||
@@ -165,16 +165,56 @@ function M.init(client, bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param client vim.lsp.Client
|
||||
--- @param bufnr integer
|
||||
--- @param name string
|
||||
--- @return string
|
||||
function M._get_and_set_name(client, bufnr, name)
|
||||
local state = state_by_group[get_group(client)] or {}
|
||||
local buf_state = (state.buffers or {})[bufnr]
|
||||
local old_name = buf_state.name
|
||||
buf_state.name = name
|
||||
return old_name
|
||||
function M._send_did_save(bufnr)
|
||||
local groups = {} ---@type table<string,vim.lsp.CTGroup>
|
||||
for _, client in pairs(vim.lsp.get_clients({ bufnr = bufnr })) do
|
||||
local group = get_group(client)
|
||||
groups[group_key(group)] = group
|
||||
end
|
||||
|
||||
local uri = vim.uri_from_bufnr(bufnr)
|
||||
local text = vim.func._memoize('concat', vim.lsp._buf_get_full_text)
|
||||
|
||||
for _, group in pairs(groups) do
|
||||
local name = api.nvim_buf_get_name(bufnr)
|
||||
local state = state_by_group[group]
|
||||
local buf_state = state.buffers[bufnr] or {}
|
||||
local old_name = buf_state.name
|
||||
buf_state.name = name
|
||||
|
||||
for _, client in pairs(state.clients) do
|
||||
if old_name and name ~= old_name then
|
||||
client:notify('textDocument/didClose', {
|
||||
textDocument = {
|
||||
uri = vim.uri_from_fname(old_name),
|
||||
},
|
||||
})
|
||||
client:notify('textDocument/didOpen', {
|
||||
textDocument = {
|
||||
version = 0,
|
||||
uri = uri,
|
||||
languageId = client.get_language_id(bufnr, vim.bo[bufnr].filetype),
|
||||
text = vim.lsp._buf_get_full_text(bufnr),
|
||||
},
|
||||
})
|
||||
util.buf_versions[bufnr] = 0
|
||||
end
|
||||
local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save')
|
||||
if save_capability then
|
||||
local included_text --- @type string?
|
||||
if type(save_capability) == 'table' and save_capability.includeText then
|
||||
included_text = text(bufnr)
|
||||
end
|
||||
client:notify('textDocument/didSave', {
|
||||
textDocument = {
|
||||
uri = uri,
|
||||
},
|
||||
text = included_text,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param buf_state vim.lsp.CTBufferState
|
||||
|
||||
@@ -815,6 +815,34 @@ describe('LSP', function()
|
||||
}
|
||||
end)
|
||||
|
||||
it('saveas sends didOpen to multiple attached servers if filename changed', function()
|
||||
local tmpfile_new = tmpname(false)
|
||||
exec_lua(create_server_definition)
|
||||
local messages = exec_lua(function()
|
||||
local server1 = _G._create_server()
|
||||
local server2 = _G._create_server()
|
||||
local client1_id = assert(vim.lsp.start({ name = 'dummy1', cmd = server1.cmd }))
|
||||
local client2_id = assert(vim.lsp.start({ name = 'dummy2', cmd = server2.cmd }))
|
||||
|
||||
vim.cmd('saveas ' .. tmpfile_new)
|
||||
|
||||
vim.lsp.get_client_by_id(client1_id):stop()
|
||||
vim.lsp.get_client_by_id(client2_id):stop()
|
||||
|
||||
return {
|
||||
server1 = server1.messages,
|
||||
server2 = server2.messages,
|
||||
}
|
||||
end)
|
||||
eq('textDocument/didClose', messages.server1[3].method)
|
||||
eq('textDocument/didOpen', messages.server1[4].method)
|
||||
eq('textDocument/didSave', messages.server1[5].method)
|
||||
|
||||
eq('textDocument/didClose', messages.server2[3].method)
|
||||
eq('textDocument/didOpen', messages.server2[4].method)
|
||||
eq('textDocument/didSave', messages.server2[5].method)
|
||||
end)
|
||||
|
||||
it('BufWritePre does not send notifications if server lacks willSave capabilities', function()
|
||||
exec_lua(create_server_definition)
|
||||
local messages = exec_lua(function()
|
||||
|
||||
Reference in New Issue
Block a user