diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index e8ffb9353e..844d4130c5 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -585,21 +585,32 @@ function lsp.enable(name, enable) end if not next(lsp._enabled_configs) then + -- If there are no remaining LSPs enabled, remove the enable autocmd. if lsp_enable_autocmd_id then api.nvim_del_autocmd(lsp_enable_autocmd_id) lsp_enable_autocmd_id = nil end - return + else + -- Only ever create autocmd once to reuse computation of config merging. + lsp_enable_autocmd_id = lsp_enable_autocmd_id + or api.nvim_create_autocmd('FileType', { + group = api.nvim_create_augroup('nvim.lsp.enable', {}), + callback = function(args) + lsp_enable_callback(args.buf) + end, + }) end - -- Only ever create autocmd once to reuse computation of config merging. - lsp_enable_autocmd_id = lsp_enable_autocmd_id - or api.nvim_create_autocmd('FileType', { - group = api.nvim_create_augroup('nvim.lsp.enable', {}), - callback = function(args) - lsp_enable_callback(args.buf) - end, - }) + -- Ensure any pre-existing buffers start/stop their LSP clients. + if enable ~= false then + vim.api.nvim_command('doautoall nvim.lsp.enable FileType') + else + for _, nm in ipairs(names) do + for _, client in ipairs(lsp.get_clients({ name = nm })) do + client:stop() + end + end + end end --- @class vim.lsp.start.Opts diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 12bdcf8208..be69491915 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -6324,7 +6324,7 @@ describe('LSP', function() ) end) - it('attaches to buffers', function() + it('attaches to buffers when they are opened', function() exec_lua(create_server_definition) local tmp1 = t.tmpname(true) @@ -6373,6 +6373,67 @@ describe('LSP', function() ) end) + it('attaches/detaches preexisting buffers', function() + exec_lua(create_server_definition) + + local tmp1 = t.tmpname(true) + local tmp2 = t.tmpname(true) + + exec_lua(function() + vim.cmd.edit(tmp1) + vim.bo.filetype = 'foo' + _G.foo_buf = vim.api.nvim_get_current_buf() + + vim.cmd.edit(tmp2) + vim.bo.filetype = 'bar' + _G.bar_buf = vim.api.nvim_get_current_buf() + + local server = _G._create_server({ + handlers = { + initialize = function(_, _, callback) + callback(nil, { capabilities = {} }) + end, + }, + }) + + vim.lsp.config('foo', { + cmd = server.cmd, + filetypes = { 'foo' }, + root_markers = { '.foorc' }, + }) + + vim.lsp.config('bar', { + cmd = server.cmd, + filetypes = { 'bar' }, + root_markers = { '.foorc' }, + }) + + vim.lsp.enable('foo') + vim.lsp.enable('bar') + end) + + eq( + { 1, 'foo', 1, 'bar' }, + exec_lua(function() + local foos = vim.lsp.get_clients({ bufnr = assert(_G.foo_buf) }) + local bars = vim.lsp.get_clients({ bufnr = assert(_G.bar_buf) }) + return { #foos, foos[1].name, #bars, bars[1].name } + end) + ) + + -- Now disable the 'foo' lsp and confirm that it's detached from the buffer it was previous + -- attached to. + exec_lua([[vim.lsp.enable('foo', false)]]) + eq( + { 0, 'foo', 1, 'bar' }, + exec_lua(function() + local foos = vim.lsp.get_clients({ bufnr = assert(_G.foo_buf) }) + local bars = vim.lsp.get_clients({ bufnr = assert(_G.bar_buf) }) + return { #foos, 'foo', #bars, bars[1].name } + end) + ) + end) + it('does not attach to buffers more than once if no root_dir', function() exec_lua(create_server_definition)