From 35cb13419ce4d092ec65ba4782c8fa363d09c6af Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sat, 7 Feb 2026 19:42:29 -0500 Subject: [PATCH] fix(conflict): keep TextChanged autocmd alive after resolution Problem: resolving the last conflict called M.detach(), which cleared attached_buffers[bufnr]. The TextChanged callback then returned true, permanently deleting the autocmd. Undo restored conflict markers but nothing re-highlighted or re-suppressed diagnostics. Solution: inline the cleanup in refresh() instead of calling detach(). Keep attached_buffers set so the autocmd survives. Re-suppress diagnostics when conflicts reappear after undo. --- lua/diffs/conflict.lua | 10 +++++++++- spec/conflict_spec.lua | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lua/diffs/conflict.lua b/lua/diffs/conflict.lua index 6522026..f0e47c6 100644 --- a/lua/diffs/conflict.lua +++ b/lua/diffs/conflict.lua @@ -214,11 +214,19 @@ end local function refresh(bufnr, config) local regions = parse_buffer(bufnr) if #regions == 0 then - M.detach(bufnr) + vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) + if diagnostics_suppressed[bufnr] then + pcall(vim.diagnostic.enable, true, { bufnr = bufnr }) + diagnostics_suppressed[bufnr] = nil + end vim.api.nvim_exec_autocmds('User', { pattern = 'DiffsConflictResolved' }) return end apply_highlights(bufnr, regions, config) + if config.disable_diagnostics and not diagnostics_suppressed[bufnr] then + pcall(vim.diagnostic.enable, false, { bufnr = bufnr }) + diagnostics_suppressed[bufnr] = true + end end ---@param bufnr integer diff --git a/spec/conflict_spec.lua b/spec/conflict_spec.lua index 128c567..75eac23 100644 --- a/spec/conflict_spec.lua +++ b/spec/conflict_spec.lua @@ -631,6 +631,39 @@ describe('conflict', function() helpers.delete_buffer(bufnr) end) + it('re-highlights when markers return after resolution', function() + local bufnr = create_file_buffer({ + '<<<<<<< HEAD', + 'local x = 1', + '=======', + 'local x = 2', + '>>>>>>> feature', + }) + vim.api.nvim_set_current_buf(bufnr) + local cfg = default_config() + conflict.attach(bufnr, cfg) + + assert.is_true(#get_extmarks(bufnr) > 0) + + vim.api.nvim_win_set_cursor(0, { 2, 0 }) + conflict.resolve_ours(bufnr, cfg) + assert.are.equal(0, #get_extmarks(bufnr)) + + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, { + '<<<<<<< HEAD', + 'local x = 1', + '=======', + 'local x = 2', + '>>>>>>> feature', + }) + vim.api.nvim_exec_autocmds('TextChanged', { buffer = bufnr }) + + assert.is_true(#get_extmarks(bufnr) > 0) + + conflict.detach(bufnr) + helpers.delete_buffer(bufnr) + end) + it('detaches after last conflict resolved', function() local bufnr = create_file_buffer({ '<<<<<<< HEAD',