diff --git a/lua/tabscope/buffer-managers/tab.lua b/lua/tabscope/buffer-managers/tab.lua index 0afd556..cbc58be 100644 --- a/lua/tabscope/buffer-managers/tab.lua +++ b/lua/tabscope/buffer-managers/tab.lua @@ -141,7 +141,7 @@ local function new(tracked_buffers) local show_another_buffer_for_window = function(tab, win) local another_buffer_to_show = -1 for buffer, _ in pairs(m._buffers_by_tab[tab]) do - if buffer ~= id then + if buffer ~= id and vim.api.nvim_buf_is_valid(buffer) then another_buffer_to_show = buffer break end diff --git a/tests/main.bats b/tests/main.bats index 3ff159e..a947150 100644 --- a/tests/main.bats +++ b/tests/main.bats @@ -91,3 +91,7 @@ EOF @test "remove local tab buffer that was last for tab" { run_case } + +@test "remove tab buffer when tracked buffer was deleted externally" { + run_case +} diff --git a/tests/test-cases.lua b/tests/test-cases.lua index 395b2eb..fa8b5db 100644 --- a/tests/test-cases.lua +++ b/tests/test-cases.lua @@ -214,4 +214,36 @@ M.remove_local_tab_buffer_that_was_last_for_tab = function() helpers.assert_listed_buffers({ "first", "second" }) end +M.remove_tab_buffer_when_tracked_buffer_was_deleted_externally = function() + local tabscope = require("tabscope") + tabscope.setup() + + -- Create buffers and visit them + local buf1 = vim.api.nvim_create_buf(true, false) + local buf2 = vim.api.nvim_create_buf(true, false) + vim.api.nvim_buf_set_name(buf1, "first") + vim.api.nvim_buf_set_name(buf2, "second") + vim.api.nvim_set_current_buf(buf1) + vim.api.nvim_set_current_buf(buf2) + + -- Wipe buf1 + vim.cmd("bwipeout! " .. buf1) + assert(not vim.api.nvim_buf_is_valid(buf1), "buf1 should be invalid after wipeout") + + -- Simulate race condition: tracking contains ONLY buf2 and the invalid buf1 + -- Use table replacement to ensure exact state, with invalid buffer ID first + local current_tab = vim.api.nvim_get_current_tabpage() + tabscope.tab_buffers._buffers_by_tab[current_tab] = {} + tabscope.tab_buffers._buffers_by_tab[current_tab][buf1] = true -- invalid, added first + tabscope.tab_buffers._buffers_by_tab[current_tab][buf2] = true -- valid, current + + -- Close buf2 - tabscope must try to show buf1 (the only other tracked buffer) + -- Without the fix: "Invalid buffer id: X" + tabscope.remove_tab_buffer() + + -- Should succeed without error + local listed = helpers.get_listed_buffers() + assert(#listed >= 1, "should have at least one buffer") +end + return M