0
0
mirror of https://github.com/vim/vim.git synced 2025-10-20 08:14:18 -04:00

patch 9.1.1557: not possible to anchor specific lines in difff mode

Problem:  not possible to anchor specific lines in difff 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: #17615

Signed-off-by: Yee Cheng Chin <ychin.git@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yee Cheng Chin
2025-07-16 20:36:54 +02:00
committed by Christian Brabandt
parent 393d398247
commit 0d9160e11c
54 changed files with 1889 additions and 579 deletions

View File

@@ -3385,6 +3385,9 @@ struct file_buffer
char_u *b_p_tc; // 'tagcase' local value
unsigned b_tc_flags; // flags for 'tagcase'
char_u *b_p_dict; // 'dictionary' local value
#ifdef FEAT_DIFF
char_u *b_p_dia; // 'diffanchors' local value
#endif
char_u *b_p_tsr; // 'thesaurus' local value
#ifdef FEAT_COMPL_FUNC
char_u *b_p_tsrfu; // 'thesaurusfunc' local value
@@ -3577,9 +3580,11 @@ struct file_buffer
* and how many lines it occupies in that buffer. When the lines are missing
* in the buffer the df_count[] is zero. This is all counted in
* buffer lines.
* There is always at least one unchanged line in between the diffs (unless
* linematch is used). Otherwise it would have been included in the diff above
* or below it.
* Usually there is always at least one unchanged line in between the diffs as
* otherwise it would have been included in the diff above or below it. When
* linematch or diff anchors are used, this is no longer guaranteed, and we may
* have adjacent diff blocks. In all cases they will not overlap, although it
* is possible to have multiple 0-count diff blocks at the same line.
* df_lnum[] + df_count[] is the lnum below the change. When in one buffer
* lines have been inserted, in the other buffer df_lnum[] is the line below
* the insertion and df_count[] is zero. When appending lines at the end of