vim-patch:9.1.1557: not possible to anchor specific lines in diff mode (#34967)

Problem:  not possible to anchor specific lines in diff mode
Solution: Add support for the anchoring lines in diff mode using the
          'diffanchor' option (Yee Cheng Chin).

Adds support for anchoring specific lines to each other while viewing a
diff. While lines are anchored, they are guaranteed to be aligned to
each other in a diff view, allowing the user to control and inform the
diff algorithm what the desired alignment is. Internally, this is done
by splitting up the buffer at each anchor and run the diff algorithm on
each split section separately, and then merge the results back for a
logically consistent diff result.

To do this, add a new "diffanchors" option that takes a list of
`{address}`, and a new "diffopt" option value "anchor". Each address
specified will be an anchor, and the user can choose to use any type of
address, including marks, line numbers, or pattern search. Anchors are
sorted by line number in each file, and it's possible to have multiple
anchors on the same line (this is useful when doing multi-buffer diff).
Update documentation to provide examples.

This is similar to Git diff's `--anchored` flag. Other diff tools like
Meld/Araxis Merge also have similar features (called "synchronization
points" or "synchronization links"). We are not using Git/Xdiff's
`--anchored` implementation here because it has a very limited API
(it requires usage of the Patience algorithm, and can only anchor
unique lines that are the same across both files).

Because the user could anchor anywhere, diff anchors could result in
adjacent diff blocks (one block is directly touching another without a
gap), if there is a change right above the anchor point. We don't want
to merge these diff blocks because we want to line up the change at the
anchor. Adjacent diff blocks were first allowed when linematch was
added, but the existing code had a lot of branched paths where
line-matched diff blocks were handled differently. As a part of this
change, refactor them to have a more unified code path that is
generalized enough to handle adjacent diff blocks correctly and without
needing to carve in exceptions all over the place.

closes: vim/vim#17615

0d9160e11c

Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
This commit is contained in:
zeertzjq
2025-07-18 08:04:32 +08:00
committed by GitHub
parent e0d179561d
commit 4f0ab9877b
22 changed files with 1590 additions and 266 deletions

View File

@@ -2836,3 +2836,489 @@ it('diff mode algorithm:histogram and inline:char with long lines #34329', funct
|
]])
end)
-- oldtest: Test_linematch_diff()
it([["linematch" in 'diffopt' implies "filler"]], function()
local screen = Screen.new(55, 20)
command('set diffopt=internal,filler,closeoff,inline:simple,linematch:30')
write_file('Xdifile1', '')
write_file('Xdifile2', '')
finally(function()
os.remove('Xdifile1')
os.remove('Xdifile2')
end)
WriteDiffFiles('// d?\n// d?', '!\nabc d!\nd!')
command('args Xdifile1 Xdifile2 | vert all | windo diffthis | 1wincmd w')
screen:expect([[
{7: }{23:-------------------------}│{7: }{22:! }|
{7: }{27:^// d?}{4: }│{7: }{27:abc d!}{4: }|
{7: }{27:// d?}{4: }│{7: }{27:d!}{4: }|
{1:~ }│{1:~ }|*15
{3:Xdifile1 }{2:Xdifile2 }|
|
]])
-- test that filler is always implicitly set by linematch
command('set diffopt-=filler')
screen:expect_unchanged()
end)
describe("'diffanchors'", function()
local screen
before_each(function()
screen = Screen.new(32, 20)
command('set winwidth=10 nohlsearch shortmess+=s')
end)
after_each(function()
os.remove('Xdifile1')
os.remove('Xdifile2')
os.remove('Xdifile3')
end)
it('works', function()
WriteDiffFiles3(
'anchorA1\n1\n2\n3\n100\n101\n102\nanchorB\n103\n104\n105',
'100\n101\n102\nanchorB\n103\n104\n105\nanchorA2\n1\n2\n3',
'100\nanchorB\n103\nanchorA3\n1\n2\n3'
)
command('args Xdifile1 Xdifile2 Xdifile3 | vert all | windo diffthis | 1wincmd w')
-- Simple diff without any anchors
command('set diffopt=filler,internal')
local s0 = [[
{7: }{22:^anchorA1}│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:1 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:2 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:3 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }100 │{7: }100 │{7: }100 |
{7: }{22:101 }│{7: }{22:101 }│{7: }{23:--------}|
{7: }{22:102 }│{7: }{22:102 }│{7: }{23:--------}|
{7: }anchorB │{7: }anchorB │{7: }anchorB |
{7: }103 │{7: }103 │{7: }103 |
{7: }{27:104}{4: }│{7: }{27:104}{4: }│{7: }{27:anchorA3}|
{7: }{4:1}{27:05}{4: }│{7: }{4:1}{27:05}{4: }│{7: }{4:1 }|
{7: }{23:--------}│{7: }{27:anchorA}{4:2}│{7: }{4:2 }|
{7: }{23:--------}│{7: }{27:1}{4: }│{7: }{27:3}{4: }|
{7: }{23:--------}│{7: }{22:2 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:3 }│{7: }{23:--------}|
{1:~ }│{1:~ }│{1:~ }|*3
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]]
screen:expect(s0)
-- Setting diffopt+=anchor or diffanchors without the other won't do anything
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect_unchanged()
command('set diffopt=filler,internal dia=1/anchorA/')
screen:expect_unchanged()
-- Use a single anchor by specifying a pattern. Test both internal and
-- external diff to make sure both paths work.
command('set diffopt=filler dia=1/anchorA/ diffopt+=anchor')
local s1 = [[
{7: }{23:--------}│{7: }{4:100 }│{7: }{4:100 }|
{7: }{23:--------}│{7: }{27:101}{4: }│{7: }{27:anchorB}{4: }|
{7: }{23:--------}│{7: }{4:10}{27:2}{4: }│{7: }{4:10}{27:3}{4: }|
{7: }{23:--------}│{7: }{22:anchorB }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:103 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:104 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:105 }│{7: }{23:--------}|
{7: }{4:^anchorA}{27:1}│{7: }{4:anchorA}{27:2}│{7: }{4:anchorA}{27:3}|
{7: }1 │{7: }1 │{7: }1 |
{7: }2 │{7: }2 │{7: }2 |
{7: }3 │{7: }3 │{7: }3 |
{7: }{22:100 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:101 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:102 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:anchorB }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:103 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:104 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:105 }│{7: }{23:--------}│{7: }{23:--------}|
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]]
screen:expect(s1)
command('set diffopt+=internal')
screen:expect_unchanged()
-- Use 2 anchors. They should be sorted by line number, so in file 2/3
-- anchorB is used before anchorA.
command('set diffopt=filler dia=1/anchorA/,1/anchorB/ diffopt+=anchor')
local s2 = [[
{7: }{23:--------}│{7: }{4:100 }│{7: }{4:100 }|
{7: }{23:--------}│{7: }{22:101 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:102 }│{7: }{23:--------}|
{7: }{4:^anchor}{27:A1}│{7: }{4:anchor}{27:B}{4: }│{7: }{4:anchor}{27:B}{4: }|
{7: }{4:1 }│{7: }{4:1}{27:03}{4: }│{7: }{4:1}{27:03}{4: }|
{7: }{27:2}{4: }│{7: }{27:104}{4: }│{7: }{23:--------}|
{7: }{27:3}{4: }│{7: }{27:105}{4: }│{7: }{23:--------}|
{7: }{22:100 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:101 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:102 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{4:anchor}{27:B}{4: }│{7: }{4:anchor}{27:A2}│{7: }{4:anchor}{27:A3}|
{7: }{4:1}{27:03}{4: }│{7: }{4:1 }│{7: }{4:1 }|
{7: }{27:104}{4: }│{7: }{27:2}{4: }│{7: }{27:2}{4: }|
{7: }{27:105}{4: }│{7: }{27:3}{4: }│{7: }{27:3}{4: }|
{1:~ }│{1:~ }│{1:~ }|*4
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]]
screen:expect(s2)
command('set diffopt+=internal')
screen:expect_unchanged()
-- Set marks and specify addresses using marks and repeat the test
command('2wincmd w | 1/anchorA/mark a')
command('1/anchorB/mark b')
command('3wincmd w | 1/anchorA/mark a')
command('1/anchorB/mark b')
command('1wincmd w | 1/anchorA/mark a')
command('1/anchorB/mark b')
command("set diffopt=filler,internal dia='a diffopt+=anchor")
screen:expect(s1)
command("set diffopt=filler,internal dia='a,'b diffopt+=anchor")
screen:expect(s2)
-- Update marks to point somewhere else. When we first set the mark the diff
-- won't be updated until we manually invoke :diffupdate.
command("set diffopt=filler,internal dia='a diffopt+=anchor")
screen:expect(s1)
command('1wincmd w | 1/anchorB/mark a')
screen:expect_unchanged()
command('diffupdate')
screen:expect([[
{7: }{22:^anchorA1}│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:1 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:2 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:3 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }100 │{7: }100 │{7: }100 |
{7: }{27:101}{4: }│{7: }{27:101}{4: }│{7: }{27:anchorB}{4: }|
{7: }{4:10}{27:2}{4: }│{7: }{4:10}{27:2}{4: }│{7: }{4:10}{27:3}{4: }|
{7: }{23:--------}│{7: }{22:anchorB }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:103 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:104 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:105 }│{7: }{23:--------}|
{7: }{4:anchor}{27:B}{4: }│{7: }{4:anchor}{27:A2}│{7: }{4:anchor}{27:A3}|
{7: }{4:1}{27:03}{4: }│{7: }{4:1 }│{7: }{4:1 }|
{7: }{27:104}{4: }│{7: }{27:2}{4: }│{7: }{27:2}{4: }|
{7: }{27:105}{4: }│{7: }{27:3}{4: }│{7: }{27:3}{4: }|
{1:~ }│{1:~ }│{1:~ }|*3
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
-- Use local diff anchors with line numbers, and repeat the same test
command('2wincmd w | setlocal dia=8')
command('3wincmd w | setlocal dia=4')
command('1wincmd w | setlocal dia=1')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect(s1)
command('2wincmd w | setlocal dia=8,4')
command('3wincmd w | setlocal dia=4,2')
command('1wincmd w | setlocal dia=1,8')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect(s2)
-- Test multiple diff anchors on the same line in file 1.
command('1wincmd w | setlocal dia=1,1')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect([[
{7: }{23:--------}│{7: }{4:100 }│{7: }{4:100 }|
{7: }{23:--------}│{7: }{22:101 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:102 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{4:anchorB }│{7: }{4:anchorB }|
{7: }{23:--------}│{7: }{4:103 }│{7: }{4:103 }|
{7: }{23:--------}│{7: }{22:104 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:105 }│{7: }{23:--------}|
{7: }{4:^anchorA}{27:1}│{7: }{4:anchorA}{27:2}│{7: }{4:anchorA}{27:3}|
{7: }1 │{7: }1 │{7: }1 |
{7: }2 │{7: }2 │{7: }2 |
{7: }3 │{7: }3 │{7: }3 |
{7: }{22:100 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:101 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:102 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:anchorB }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:103 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:104 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:105 }│{7: }{23:--------}│{7: }{23:--------}|
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
-- Test that if one file has fewer diff anchors than others. Vim should only
-- use the minimum in this case.
command('1wincmd w | setlocal dia=8')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect([[
{7: }{22:^anchorA1}│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:1 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:2 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:3 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }100 │{7: }100 │{7: }100 |
{7: }{22:101 }│{7: }{22:101 }│{7: }{23:--------}|
{7: }{22:102 }│{7: }{22:102 }│{7: }{23:--------}|
{7: }anchorB │{7: }anchorB │{7: }anchorB |
{7: }103 │{7: }103 │{7: }103 |
{7: }{27:104}{4: }│{7: }{27:104}{4: }│{7: }{27:anchorA3}|
{7: }{4:1}{27:05}{4: }│{7: }{4:1}{27:05}{4: }│{7: }{4:1 }|
{7: }{23:--------}│{7: }{27:anchorA}{4:2}│{7: }{4:2 }|
{7: }{23:--------}│{7: }{27:1}{4: }│{7: }{27:3}{4: }|
{7: }{23:--------}│{7: }{22:2 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:3 }│{7: }{23:--------}|
{1:~ }│{1:~ }│{1:~ }|*3
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
-- $+1 should anchor everything past the last line
command('1wincmd w | setlocal dia=$+1')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect([[
{7: }{22:^anchorA1}│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:1 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:2 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:3 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }100 │{7: }100 │{7: }100 |
{7: }{4:101 }│{7: }{4:101 }│{7: }{23:--------}|
{7: }{4:102 }│{7: }{4:102 }│{7: }{23:--------}|
{7: }{22:anchorB }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:103 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:104 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:105 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{23:--------}│{7: }{4:anchorB }│{7: }{4:anchorB }|
{7: }{23:--------}│{7: }{4:103 }│{7: }{4:103 }|
{7: }{23:--------}│{7: }{27:104}{4: }│{7: }{27:anchorA3}|
{7: }{23:--------}│{7: }{4:1}{27:05}{4: }│{7: }{4:1 }|
{7: }{23:--------}│{7: }{27:anchorA}{4:2}│{7: }{4:2 }|
{7: }{23:--------}│{7: }{27:1}{4: }│{7: }{27:3}{4: }|
{7: }{23:--------}│{7: }{22:2 }│{7: }{23:--------}|
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
-- Sorting of diff anchors should work with multiple anchors
command('1wincmd w | setlocal dia=1,10,8,2')
command('2wincmd w | setlocal dia=1,2,3,4')
command('3wincmd w | setlocal dia=4,3,2,1')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect([[
{7: }{27:anchorA1}│{7: }{27:100}{4: }│{7: }{27:^100}{4: }|
{7: }{27:1}{4: }│{7: }{27:101}{4: }│{7: }{27:anchorB}{4: }|
{7: }{22:2 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:3 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:100 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:101 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{22:102 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{27:anchorB}{4: }│{7: }{27:102}{4: }│{7: }{27:103}{4: }|
{7: }{22:103 }│{7: }{23:--------}│{7: }{23:--------}|
{7: }{27:104}{4: }│{7: }{27:anchorB}{4: }│{7: }{27:anchorA3}|
{7: }{4:1}{27:05}{4: }│{7: }{4:1}{27:03}{4: }│{7: }{4:1 }|
{7: }{23:--------}│{7: }{27:104}{4: }│{7: }{27:2}{4: }|
{7: }{23:--------}│{7: }{27:105}{4: }│{7: }{27:3}{4: }|
{7: }{23:--------}│{7: }{22:anchorA2}│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:1 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:2 }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{22:3 }│{7: }{23:--------}|
{1:~ }│{1:~ }│{1:~ }|
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
-- Intentionally set an invalid anchor with wrong line number. Should fall
-- back to treat it as if no anchors are used at all.
command('1wincmd w | setlocal dia=1,10,8,2,1000 | silent! diffupdate')
screen:expect(s0)
end)
-- oldtest: Test_diffanchors_scrollbind_topline()
it('scrollbind works with adjacent diff blocks', function()
WriteDiffFiles('anchor1\ndiff1a\nanchor2', 'anchor1\ndiff2a\nanchor2')
command('args Xdifile1 Xdifile2 | vert all | windo diffthis | 1wincmd w')
command('1wincmd w | setlocal dia=2')
command('2wincmd w | setlocal dia=3')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect([[
{7: }anchor1 │{7: }^anchor1 |
{7: }{23:-------------}│{7: }{22:diff2a }|
{7: }{22:diff1a }│{7: }{23:--------------}|
{7: }anchor2 │{7: }anchor2 |
{1:~ }│{1:~ }|*14
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{23:-------------}│{7: }{22:^diff2a }|
{7: }{22:diff1a }│{7: }{23:--------------}|
{7: }anchor2 │{7: }anchor2 |
{1:~ }│{1:~ }|*15
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{22:diff1a }│{7: }{23:--------------}|
{7: }anchor2 │{7: }^anchor2 |
{1:~ }│{1:~ }|*16
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }anchor2 │{7: }^anchor2 |
{1:~ }│{1:~ }|*17
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
-- Also test no-filler
feed('gg')
command('set diffopt=filler,internal diffopt+=anchor diffopt-=filler')
screen:expect([[
{7: }anchor1 │{7: }^anchor1 |
{7: }{22:diff1a }│{7: }{22:diff2a }|
{7: }anchor2 │{7: }anchor2 |
{1:~ }│{1:~ }|*15
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{22:diff1a }│{7: }{22:^diff2a }|
{7: }anchor2 │{7: }anchor2 |
{1:~ }│{1:~ }|*16
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }anchor2 │{7: }^anchor2 |
{1:~ }│{1:~ }|*17
{2:Xdifile1 }{3:Xdifile2 }|
|
]])
end)
-- oldtest: Test_diffanchors_scrollbind_topline2()
it('scrollbind works with 3 files and overlapping diff blocks', function()
WriteDiffFiles3(
'anchor1',
'diff2a\ndiff2b\ndiff2c\ndiff2d\nanchor2',
'diff3a\ndiff3c\ndiff3d\nanchor3\ndiff3e'
)
command('args Xdifile1 Xdifile2 Xdifile3 | vert all | windo diffthis | 1wincmd w')
command('1wincmd w | setlocal dia=1,1,2')
command('2wincmd w | setlocal dia=3,5,6')
command('3wincmd w | setlocal dia=2,4,5')
command('set diffopt=filler,internal diffopt+=anchor')
screen:expect([[
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:a }│{7: }{4:^diff}{27:3}{4:a }|
{7: }{23:--------}│{7: }{22:diff2b }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:c }│{7: }{4:diff}{27:3}{4:c }|
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:d }│{7: }{4:diff}{27:3}{4:d }|
{7: }{4:anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{7: }{23:--------}│{7: }{23:--------}│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*12
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
command('1wincmd w')
feed('<C-E>')
screen:expect([[
{7: }{23:--------}│{7: }{22:diff2b }│{7: }{23:--------}|
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:c }│{7: }{4:diff}{27:3}{4:c }|
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:d }│{7: }{4:diff}{27:3}{4:d }|
{7: }{4:^anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{7: }{23:--------}│{7: }{23:--------}│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*13
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:c }│{7: }{4:diff}{27:3}{4:c }|
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:d }│{7: }{4:diff}{27:3}{4:d }|
{7: }{4:^anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{7: }{23:--------}│{7: }{23:--------}│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*14
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{23:--------}│{7: }{4:diff}{27:2}{4:d }│{7: }{4:diff}{27:3}{4:d }|
{7: }{4:^anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{7: }{23:--------}│{7: }{23:--------}│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*15
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{4:^anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{7: }{23:--------}│{7: }{23:--------}│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*16
{3:Xdifile1 }{2:Xdifile2 Xdifile3 }|
|
]])
-- Also test no-filler
command('3wincmd w')
feed('gg')
command('set diffopt=filler,internal diffopt+=anchor diffopt-=filler')
screen:expect([[
{7: }{4:anchor}{27:1}{4: }│{7: }{4:diff}{27:2}{4:a }│{7: }{4:^diff}{27:3}{4:a }|
{1:~ }│{7: }{22:diff2b }│{7: }{4:diff}{27:3}{4:c }|
{1:~ }│{7: }{4:diff}{27:2}{4:c }│{7: }{4:diff}{27:3}{4:d }|
{1:~ }│{7: }{4:diff}{27:2}{4:d }│{7: }{4:anchor}{27:3}{4: }|
{1:~ }│{7: }{4:anchor}{27:2}{4: }│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*13
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{4:anchor}{27:1}{4: }│{7: }{4:diff}{27:2}{4:c }│{7: }{4:^diff}{27:3}{4:c }|
{1:~ }│{7: }{4:diff}{27:2}{4:d }│{7: }{4:diff}{27:3}{4:d }|
{1:~ }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{1:~ }│{1:~ }│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*14
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{4:anchor}{27:1}{4: }│{7: }{4:diff}{27:2}{4:d }│{7: }{4:^diff}{27:3}{4:d }|
{1:~ }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:anchor}{27:3}{4: }|
{1:~ }│{1:~ }│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*15
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{4:anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{4:^anchor}{27:3}{4: }|
{1:~ }│{1:~ }│{7: }{22:diff3e }|
{1:~ }│{1:~ }│{1:~ }|*16
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
feed('<C-E>')
screen:expect([[
{7: }{4:anchor}{27:1}{4: }│{7: }{4:anchor}{27:2}{4: }│{7: }{22:^diff3e }|
{1:~ }│{1:~ }│{1:~ }|*17
{2:Xdifile1 Xdifile2 }{3:Xdifile3 }|
|
]])
end)
end)