Skip to content

Commit ac9970e

Browse files
committed
fix: prevent infinite detach/re-attach loop on non-buflisted buffers
Fixes #576
1 parent 7bc9620 commit ac9970e

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

lua/copilot/client/init.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ local function on_buf_enter(bufnr)
184184
-- This is to handle the case where the filetype changes after the buffer is already attached,
185185
-- causing the LSP to raise an error
186186
local previous_ft = util.get_buffer_previous_ft(bufnr)
187-
if previous_ft and (previous_ft ~= vim.bo[bufnr].filetype) then
187+
if previous_ft and vim.bo[bufnr].buflisted and (previous_ft ~= vim.bo[bufnr].filetype) then
188188
logger.trace("filetype changed, detaching and re-attaching")
189189
M.buf_detach_if_attached(bufnr)
190190
end

tests/test_client.lua

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,4 +436,47 @@ T["client()"]["disabled copilot does not spam warnings on buffer enter"] = funct
436436
MiniTest.expect.equality(count, 0)
437437
end
438438

439+
T["client()"]["on_buf_enter skips filetype check for non-buflisted buffers"] = function()
440+
child.configure_copilot()
441+
442+
-- Create a non-buflisted buffer with a filetype mismatch and trigger BufEnter.
443+
-- This simulates floating windows / preview buffers that should not trigger
444+
-- the filetype-change detach+re-attach cycle.
445+
child.lua([[
446+
local util = require("copilot.util")
447+
448+
local buf = vim.api.nvim_create_buf(false, true) -- nobuflisted, scratch
449+
vim.api.nvim_set_option_value("filetype", "lua", { buf = buf })
450+
451+
-- Manually set previous_ft to simulate a buffer that was previously attached.
452+
-- buf_attach won't succeed for non-buflisted buffers (should_attach rejects them),
453+
-- so previous_ft wouldn't normally be set. In the real bug scenario, this state
454+
-- can be reached through various pathways.
455+
util.set_buffer_previous_ft(buf, "lua")
456+
457+
-- Change filetype on same non-buflisted buffer
458+
vim.api.nvim_set_option_value("filetype", "python", { buf = buf })
459+
460+
-- Trigger BufEnter (simulating entering the buffer)
461+
vim.api.nvim_exec_autocmds("BufEnter", { buffer = buf })
462+
463+
-- Wait for scheduled callbacks to execute
464+
vim.wait(200, function() return false end, 10)
465+
]])
466+
467+
-- The filetype change should NOT cause detach+re-attach for non-buflisted buffers
468+
local detach_was_called = child.lua([[
469+
local log_content = ""
470+
local logfile = io.open("./tests/logs/test_client.log", "r")
471+
if logfile then
472+
log_content = logfile:read("*a")
473+
logfile:close()
474+
end
475+
-- If the guard works, we should NOT see "filetype changed" for non-buflisted buffers
476+
return log_content:find("filetype changed, detaching and re%-attaching") ~= nil
477+
]])
478+
479+
MiniTest.expect.equality(detach_was_called, false)
480+
end
481+
439482
return T

0 commit comments

Comments
 (0)