mirror of
https://github.com/neovim/neovim
synced 2025-07-20 13:22:26 +00:00
fix(lsp): check if buffer was detached in on_init callback (#28914)
Co-authored-by: Jongwook Choi <wookayin@gmail.com>
This commit is contained in:
@ -612,7 +612,10 @@ function Client:initialize()
|
|||||||
self:_run_callbacks(self._on_init_cbs, lsp.client_errors.ON_INIT_CALLBACK_ERROR, self, result)
|
self:_run_callbacks(self._on_init_cbs, lsp.client_errors.ON_INIT_CALLBACK_ERROR, self, result)
|
||||||
|
|
||||||
for buf in pairs(reattach_bufs) do
|
for buf in pairs(reattach_bufs) do
|
||||||
self:_on_attach(buf)
|
-- The buffer may have been detached in the on_init callback.
|
||||||
|
if self.attached_buffers[buf] then
|
||||||
|
self:_on_attach(buf)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
|
@ -70,8 +70,8 @@ before_each(function()
|
|||||||
inlayHintProvider = true,
|
inlayHintProvider = true,
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/inlayHint'] = function()
|
['textDocument/inlayHint'] = function(_, _, callback)
|
||||||
return vim.json.decode(response)
|
callback(nil, vim.json.decode(response))
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -106,8 +106,8 @@ describe('vim.lsp.inlay_hint', function()
|
|||||||
inlayHintProvider = true,
|
inlayHintProvider = true,
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/inlayHint'] = function()
|
['textDocument/inlayHint'] = function(_, _, callback)
|
||||||
return {}
|
callback(nil, {})
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -206,8 +206,8 @@ describe('vim.lsp.inlay_hint', function()
|
|||||||
inlayHintProvider = true,
|
inlayHintProvider = true,
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/inlayHint'] = function()
|
['textDocument/inlayHint'] = function(_, _, callback)
|
||||||
return { expected2 }
|
callback(nil, { expected2 })
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -95,11 +95,11 @@ describe('semantic token highlighting', function()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/semanticTokens/full'] = function()
|
['textDocument/semanticTokens/full'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(response)
|
callback(nil, vim.fn.json_decode(response))
|
||||||
end,
|
end,
|
||||||
['textDocument/semanticTokens/full/delta'] = function()
|
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(edit_response)
|
callback(nil, vim.fn.json_decode(edit_response))
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -560,11 +560,11 @@ describe('semantic token highlighting', function()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/semanticTokens/full'] = function()
|
['textDocument/semanticTokens/full'] = function(_, _, callback)
|
||||||
return nil
|
callback(nil, nil)
|
||||||
end,
|
end,
|
||||||
['textDocument/semanticTokens/full/delta'] = function()
|
['textDocument/semanticTokens/full/delta'] = function()
|
||||||
return nil
|
callback(nil, nil)
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -608,11 +608,11 @@ describe('semantic token highlighting', function()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/semanticTokens/full'] = function()
|
['textDocument/semanticTokens/full'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(response)
|
callback(nil, vim.fn.json_decode(response))
|
||||||
end,
|
end,
|
||||||
['textDocument/semanticTokens/full/delta'] = function()
|
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(edit_response)
|
callback(nil, vim.fn.json_decode(edit_response))
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1075,8 +1075,8 @@ b = "as"]],
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/semanticTokens/full'] = function()
|
['textDocument/semanticTokens/full'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(resp)
|
callback(nil, vim.fn.json_decode(resp))
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1461,11 +1461,11 @@ int main()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/semanticTokens/full'] = function()
|
['textDocument/semanticTokens/full'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(resp1)
|
callback(nil, vim.fn.json_decode(resp1))
|
||||||
end,
|
end,
|
||||||
['textDocument/semanticTokens/full/delta'] = function()
|
['textDocument/semanticTokens/full/delta'] = function(_, _, callback)
|
||||||
return vim.fn.json_decode(resp2)
|
callback(nil, vim.fn.json_decode(resp2))
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -39,8 +39,7 @@ M.create_server_definition = [[
|
|||||||
})
|
})
|
||||||
local handler = handlers[method]
|
local handler = handlers[method]
|
||||||
if handler then
|
if handler then
|
||||||
local response, err = handler(method, params)
|
handler(method, params, callback)
|
||||||
callback(err, response)
|
|
||||||
elseif method == 'initialize' then
|
elseif method == 'initialize' then
|
||||||
callback(nil, {
|
callback(nil, {
|
||||||
capabilities = opts.capabilities or {}
|
capabilities = opts.capabilities or {}
|
||||||
|
@ -501,6 +501,35 @@ describe('LSP', function()
|
|||||||
eq(true, result.detach_called)
|
eq(true, result.detach_called)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('should not re-attach buffer if it was deleted in on_init #28575', function()
|
||||||
|
clear()
|
||||||
|
exec_lua(create_server_definition)
|
||||||
|
exec_lua([[
|
||||||
|
local server = _create_server({
|
||||||
|
handlers = {
|
||||||
|
initialize = function(method, params, callback)
|
||||||
|
vim.schedule(function()
|
||||||
|
callback(nil, { capabilities = {} })
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
})
|
||||||
|
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||||
|
local on_init_called = false
|
||||||
|
local client_id = vim.lsp.start({
|
||||||
|
name = 'detach-dummy',
|
||||||
|
cmd = server.cmd,
|
||||||
|
on_init = function()
|
||||||
|
vim.api.nvim_buf_delete(bufnr, {})
|
||||||
|
on_init_called = true
|
||||||
|
end
|
||||||
|
})
|
||||||
|
vim.lsp.buf_attach_client(bufnr, client_id)
|
||||||
|
local ok = vim.wait(1000, function() return on_init_called end)
|
||||||
|
assert(ok, "on_init was not called")
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
it('client should return settings via workspace/configuration handler', function()
|
it('client should return settings via workspace/configuration handler', function()
|
||||||
local expected_handlers = {
|
local expected_handlers = {
|
||||||
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
|
{ NIL, {}, { method = 'shutdown', client_id = 1 } },
|
||||||
@ -670,7 +699,7 @@ describe('LSP', function()
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
['textDocument/willSaveWaitUntil'] = function()
|
['textDocument/willSaveWaitUntil'] = function(_, _, callback)
|
||||||
local text_edit = {
|
local text_edit = {
|
||||||
range = {
|
range = {
|
||||||
start = { line = 0, character = 0 },
|
start = { line = 0, character = 0 },
|
||||||
@ -678,7 +707,7 @@ describe('LSP', function()
|
|||||||
},
|
},
|
||||||
newText = 'Hello'
|
newText = 'Hello'
|
||||||
}
|
}
|
||||||
return { text_edit, }
|
callback(nil, { text_edit, })
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -4144,8 +4173,8 @@ describe('LSP', function()
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
["textDocument/codeAction"] = function()
|
["textDocument/codeAction"] = function(_, _, callback)
|
||||||
return {
|
callback(nil, {
|
||||||
{
|
{
|
||||||
title = "Code Action 1",
|
title = "Code Action 1",
|
||||||
command = {
|
command = {
|
||||||
@ -4153,10 +4182,10 @@ describe('LSP', function()
|
|||||||
command = "command:1",
|
command = "command:1",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
end,
|
end,
|
||||||
["codeAction/resolve"] = function()
|
["codeAction/resolve"] = function(_, _, callback)
|
||||||
return nil, "resolve failed"
|
callback("resolve failed", nil)
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -4344,7 +4373,7 @@ describe('LSP', function()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
["textDocument/codeLens"] = function(method, params)
|
["textDocument/codeLens"] = function(method, params, callback)
|
||||||
local lenses = {
|
local lenses = {
|
||||||
{
|
{
|
||||||
range = {
|
range = {
|
||||||
@ -4357,7 +4386,7 @@ describe('LSP', function()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return lenses
|
callback(nil, lenses)
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -4665,13 +4694,13 @@ describe('LSP', function()
|
|||||||
},
|
},
|
||||||
handlers = {
|
handlers = {
|
||||||
---@return lsp.Location[]
|
---@return lsp.Location[]
|
||||||
['textDocument/definition'] = function()
|
['textDocument/definition'] = function(_, _, callback)
|
||||||
return { _G.mock_locations[1] }
|
callback(nil, { _G.mock_locations[1] })
|
||||||
end,
|
end,
|
||||||
---@return lsp.WorkspaceSymbol[]
|
---@return lsp.WorkspaceSymbol[]
|
||||||
['workspace/symbol'] = function(_, request)
|
['workspace/symbol'] = function(_, request, callback)
|
||||||
assert(request.query == 'foobar')
|
assert(request.query == 'foobar')
|
||||||
return {
|
callback(nil, {
|
||||||
{
|
{
|
||||||
name = 'foobar',
|
name = 'foobar',
|
||||||
kind = 13, ---@type lsp.SymbolKind
|
kind = 13, ---@type lsp.SymbolKind
|
||||||
@ -4682,7 +4711,7 @@ describe('LSP', function()
|
|||||||
kind = 12, ---@type lsp.SymbolKind
|
kind = 12, ---@type lsp.SymbolKind
|
||||||
location = _G.mock_locations[2],
|
location = _G.mock_locations[2],
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user