diff --git a/.agents/skills/verify-diff-lifecycle/covered.lock b/.agents/skills/verify-diff-lifecycle/covered.lock index 6bbd35bf3..88e0fe98a 100644 --- a/.agents/skills/verify-diff-lifecycle/covered.lock +++ b/.agents/skills/verify-diff-lifecycle/covered.lock @@ -3,7 +3,7 @@ file lua/claudecode/config.lua b4eaec92b6d04b40 == lua/claudecode/cwd.lua file lua/claudecode/cwd.lua 55d26ea362173afa == lua/claudecode/diff.lua -file lua/claudecode/diff.lua 53c0f9034a7df662 +file lua/claudecode/diff.lua a21129cdc802e417 block resolve_saved 46d5f3f732711fe1 block resolve_rejected c7a620816abff9a1 block open_blocking 92067df7f9d4d4d9 diff --git a/lua/claudecode/diff.lua b/lua/claudecode/diff.lua index a0a9f55b3..5875c295f 100644 --- a/lua/claudecode/diff.lua +++ b/lua/claudecode/diff.lua @@ -813,7 +813,8 @@ function M._open_native_diff(old_file_path, new_file_path, new_file_contents, ta vim.cmd("edit " .. vim.fn.fnameescape(old_file_path)) vim.cmd("diffthis") create_split() - vim.cmd("edit " .. vim.fn.fnameescape(tmp_file)) + -- Without a swap file, the rename below cannot meet another Neovim's swap file for " (New)" (E325). + vim.cmd("noswapfile edit " .. vim.fn.fnameescape(tmp_file)) vim.api.nvim_buf_set_name(0, new_file_path .. " (New)") -- Propagate filetype to the proposed buffer for proper syntax highlighting (#20) diff --git a/tests/integration/diff_legacy_swap_spec.lua b/tests/integration/diff_legacy_swap_spec.lua new file mode 100644 index 000000000..7487d4fa1 --- /dev/null +++ b/tests/integration/diff_legacy_swap_spec.lua @@ -0,0 +1,66 @@ +-- Real-Neovim check that the legacy diff.open_diff opens its proposal when another Neovim left a swap file for the +-- proposal's name (" (New)"). Swap files need a real Neovim, so under busted's mock vim this is pending; +-- scripts/run_integration_tests_individually.sh runs it in Neovim. +if vim == nil or vim.fn.has("nvim") ~= 1 then + describe("legacy open_diff and a swap file for its proposal", function() + pending("needs a real Neovim") + end) + return +end + +describe("legacy open_diff and a swap file for its proposal", function() + local diff = require("claudecode.diff") + local dir, swap_dir, path, saved_directory + + before_each(function() + dir = vim.fn.tempname() + swap_dir = dir .. "/swap" + vim.fn.mkdir(swap_dir, "p") + path = dir .. "/foo.lua" + vim.fn.writefile({ "local a = 1" }, path) + saved_directory = vim.o.directory + vim.o.directory = swap_dir .. "//" + diff.setup({ diff_opts = {} }) + end) + + after_each(function() + vim.cmd("silent! diffoff!") + vim.cmd("silent! only") + vim.cmd("silent! %bwipeout!") + vim.o.directory = saved_directory + vim.fn.delete(dir, "rf") + end) + + it("opens the proposal when a killed Neovim left a swap file for ' (New)'", function() + -- Another Neovim changes a buffer named " (New)", so its swap file records that name, and is killed. + vim.fn.system({ + vim.v.progpath, + "--headless", + "-u", + "NONE", + "-i", + "NONE", + "--cmd", + "set directory=" .. vim.fn.fnameescape(swap_dir) .. "//", + "-c", + "edit " .. vim.fn.fnameescape(path .. " (New)"), + "-c", + "call setline(1, 'unsaved')", + "-c", + "preserve", + "-c", + "lua (vim.uv or vim.loop).kill(vim.fn.getpid(), 9)", + }) + assert.are.equal(1, #vim.fn.glob(swap_dir .. "/*", false, true), "the killed Neovim left its swap file") + + vim.cmd("edit " .. vim.fn.fnameescape(path)) + local ok, result = pcall(diff.open_diff, path, path, "local a = 2\n", "legacy swap") + + assert.is_true(ok, tostring(result)) + assert.is_true(result.success) + local proposal = vim.api.nvim_get_current_buf() + assert.are.equal(path .. " (New)", vim.api.nvim_buf_get_name(proposal)) + assert.is_false(vim.bo[proposal].swapfile) + assert.are.equal("", vim.fn.swapname(proposal)) + end) +end)