feat: unified diff conflict resolution for unmerged files (#99)
## Problem Pressing `du` on a `UU` (unmerged) file in the fugitive status buffer had no effect. There was no way to see a proper ours-vs-theirs diff with syntax highlighting and intra-line changes, or to resolve conflicts from within a unified diff view. Additionally, pressing `du` on a section header containing only unmerged files showed "no changes in section" because `git diff` produces combined (`diff --cc`) output for unmerged files, which was stripped entirely. ## Solution Fetch `:2:` (ours) and `:3:` (theirs) from the git index and generate a standard unified diff. The existing highlight pipeline (treesitter + intra-line) applies automatically. Resolution keymaps (`doo`/`dot`/`dob`/`don`) on hunks in the diff view write changes back to the working file's conflict markers. Navigation (`]x`/`[x`) jumps between unresolved conflict hunks. For section diffs, combined diff entries are now replaced with generated ours-vs-theirs unified diffs instead of being stripped. Works for merge, cherry-pick, and rebase conflicts — git populates `:2:`/`:3:` the same way for all three. Closes #61
This commit is contained in:
parent
49fc446aae
commit
a2053a132b
8 changed files with 1287 additions and 28 deletions
|
|
@ -40,6 +40,78 @@ describe('commands', function()
|
|||
end)
|
||||
end)
|
||||
|
||||
describe('filter_combined_diffs', function()
|
||||
it('strips diff --cc entries entirely', function()
|
||||
local lines = {
|
||||
'diff --cc main.lua',
|
||||
'index d13ab94,b113aee..0000000',
|
||||
'--- a/main.lua',
|
||||
'+++ b/main.lua',
|
||||
'@@@ -1,7 -1,7 +1,11 @@@',
|
||||
' local M = {}',
|
||||
'++<<<<<<< HEAD',
|
||||
' + return 1',
|
||||
'++=======',
|
||||
'+ return 2',
|
||||
'++>>>>>>> theirs',
|
||||
' end',
|
||||
}
|
||||
local result = commands.filter_combined_diffs(lines)
|
||||
assert.are.equal(0, #result)
|
||||
end)
|
||||
|
||||
it('preserves diff --git entries', function()
|
||||
local lines = {
|
||||
'diff --git a/file.lua b/file.lua',
|
||||
'--- a/file.lua',
|
||||
'+++ b/file.lua',
|
||||
'@@ -1,3 +1,3 @@',
|
||||
' local M = {}',
|
||||
'-local x = 1',
|
||||
'+local x = 2',
|
||||
' return M',
|
||||
}
|
||||
local result = commands.filter_combined_diffs(lines)
|
||||
assert.are.equal(8, #result)
|
||||
assert.are.same(lines, result)
|
||||
end)
|
||||
|
||||
it('strips combined but keeps unified in mixed output', function()
|
||||
local lines = {
|
||||
'diff --cc conflict.lua',
|
||||
'index aaa,bbb..000',
|
||||
'@@@ -1,1 -1,1 +1,5 @@@',
|
||||
'++<<<<<<< HEAD',
|
||||
'diff --git a/clean.lua b/clean.lua',
|
||||
'--- a/clean.lua',
|
||||
'+++ b/clean.lua',
|
||||
'@@ -1,1 +1,1 @@',
|
||||
'-old',
|
||||
'+new',
|
||||
}
|
||||
local result = commands.filter_combined_diffs(lines)
|
||||
assert.are.equal(6, #result)
|
||||
assert.are.equal('diff --git a/clean.lua b/clean.lua', result[1])
|
||||
assert.are.equal('+new', result[6])
|
||||
end)
|
||||
|
||||
it('returns empty for empty input', function()
|
||||
local result = commands.filter_combined_diffs({})
|
||||
assert.are.equal(0, #result)
|
||||
end)
|
||||
|
||||
it('returns empty when all entries are combined', function()
|
||||
local lines = {
|
||||
'diff --cc a.lua',
|
||||
'some content',
|
||||
'diff --cc b.lua',
|
||||
'more content',
|
||||
}
|
||||
local result = commands.filter_combined_diffs(lines)
|
||||
assert.are.equal(0, #result)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('find_hunk_line', function()
|
||||
it('finds matching @@ header and returns target line', function()
|
||||
local diff_lines = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue