[vim/vim] When diffing two windows, lines containing differences are often misaligned (Issue #18670)

31 views
Skip to first unread message

Gary Johnson

unread,
Oct 30, 2025, 4:34:21 PMOct 30
to vim/vim, Subscribed
ghgary created an issue (vim/vim#18670)

Steps to reproduce

  1. I wanted to check that in my directory of bank statements, the base names of the .csv files were the same as the .txt files. (My bank uses only one basename for downloads, so I have to manually name them.) I was surprised to find that the differences were not aligned, making it difficult to compare the two sets of files. For this bug report, I listed the .csv files and .txt files into two text files, ls-csv.txt and ls-txt.txt, which are attached.
  2. Execute at a shell prompt: vimdiff -N -u NONE -i NONE ls-txt.txt ls-csv.txt
  3. Note that the files in the right window have their "csv" suffixes highlighted in red, while most of the other characters in the file names have the purple differing-lines background color. The matching lines in the left window are at the bottom of the buffer rather than alongside the corresponding lines on the right.

ls-csv.txt
ls-txt.txt

Expected behaviour

I expect the lines identified as different to be displayed on the same screen lines as they usually are.

The diff algorithm clearly has identified the differing lines and the differences between them as it shows the differing lines and their differences in both windows. However, the lines are not always aligned side-by-side as they should be and as they were before 9.1.1753.

I've seen numerous instances of this problem before, but this time I had time to investigate and report it. It has existed since 9.1.1753.

Version of Vim

9.1.1839

Environment

Operating system: Ubuntu 24.04.3 LTS
Terminal: XTerm(389)
Value of $TERM: xterm-256color
Shell: GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)

Logs and stack traces


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/18670@github.com>

Maxim Kim

unread,
Oct 30, 2025, 7:23:26 PMOct 30
to vim/vim, Subscribed
habamax left a comment (vim/vim#18670)

I get this with linematch:100:

image.png (view on web)
set diffopt+=hiddenoff,algorithm:histogram,linematch:100


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/18670/3470688225@github.com>

Maxim Kim

unread,
Oct 30, 2025, 8:21:29 PMOct 30
to vim/vim, Subscribed
habamax left a comment (vim/vim#18670)

I have just tried version before v9.1.1753 and it is worse than a current one provided you have set big enough linematch. However, with default linematch older version looks a bit better.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/18670/3470789450@github.com>

Maxim Kim

unread,
Oct 30, 2025, 8:27:07 PMOct 30
to vim/vim, Subscribed
habamax left a comment (vim/vim#18670)

sidenote, looks like there is an issue with mouse wheel scrolling of non active diff window: it doesn't scroll active window -- scrollbind has no effect.

https://asciinema.org/a/FkPvBsk5NXzGR9WEnuoSl9t2J


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/18670/3470804499@github.com>

Gary Johnson

unread,
Oct 30, 2025, 9:17:44 PMOct 30
to reply+ACY5DGHTNYMAIFZMX3...@reply.github.com, vim...@googlegroups.com
On 2025-10-30, Maxim Kim (Vim Github Repository) wrote:
> ●habamax left a comment (vim/vim#18670)
>
> I get this with linematch:100:
>
> image.png (view on web)
>
> set diffopt+=hiddenoff,algorithm:histogram,linematch:100

Yes, that's how I was expecting it to look. I didn't know about
linematch. Thanks.

I was expecting diff to just work, as it always has, without tweaks.
Otherwise, I like the new algorithm in that it's much easier to see
multiple differences in a line.

I guess I can close this as not a bug.

Regards,
Gary

vim-dev ML

unread,
Oct 30, 2025, 9:18:14 PMOct 30
to vim/vim, vim-dev ML, Your activity
vim-ml left a comment (vim/vim#18670)


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/18670/3470920965@github.com>

Maxim Kim

unread,
Oct 30, 2025, 9:24:35 PMOct 30
to vim/vim, vim-dev ML, Comment
habamax left a comment (vim/vim#18670)

I was expecting diff to just work, as it always has, without tweaks. Otherwise, I like the new algorithm in that it's much easier to see multiple differences in a line.

I am not 100% sure this is a good idea, but what about increasing default linematch value?


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3470936824@github.com>

zeertzjq

unread,
Oct 30, 2025, 9:26:44 PMOct 30
to vim/vim, vim-dev ML, Comment
zeertzjq left a comment (vim/vim#18670)

linematch isn't enabled by default.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3470943341@github.com>

Maxim Kim

unread,
Oct 30, 2025, 9:28:53 PMOct 30
to vim/vim, vim-dev ML, Comment
habamax left a comment (vim/vim#18670)

linematch isn't enabled by default.

yes, but even if enabled with suggested 60, it wouldn't help in OP's scenario:

image.png (view on web)

Although with 60 it looks like pre v9.1.1753


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3470949451@github.com>

Gary Johnson

unread,
Oct 30, 2025, 10:02:10 PMOct 30
to vim/vim, vim-dev ML, Comment
ghgary left a comment (vim/vim#18670)

linematch isn't enabled by default.

It certainly seems to be. It doesn't appear in 'diffopts', but the diff feature now behaves as if it is enabled. The alignment between corresponding lines in two diffed windows is definitely broken if linediff is not set at all.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471003494@github.com>

Maxim Kim

unread,
Oct 30, 2025, 10:13:39 PMOct 30
to vim/vim, vim-dev ML, Comment
habamax left a comment (vim/vim#18670)

@ychin fyi


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471025302@github.com>

Yee Cheng Chin

unread,
Oct 30, 2025, 11:36:18 PMOct 30
to vim/vim, vim-dev ML, Comment
ychin left a comment (vim/vim#18670)

sidenote, looks like there is an issue with mouse wheel scrolling of non active diff window: it doesn't scroll active window -- scrollbind has no effect.

Yes, it has been annoying me for ages! Been meaning to look into fixing it.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471190346@github.com>

zeertzjq

unread,
Oct 30, 2025, 11:50:26 PMOct 30
to vim/vim, vim-dev ML, Comment
zeertzjq left a comment (vim/vim#18670)

sidenote, looks like there is an issue with mouse wheel scrolling of non active diff window: it doesn't scroll active window -- scrollbind has no effect.

Yes, it has been annoying me for ages! Been meaning to look into fixing it.

See #13189


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471225509@github.com>

Maxim Kim

unread,
Oct 31, 2025, 12:14:58 AMOct 31
to vim/vim, vim-dev ML, Comment
habamax left a comment (vim/vim#18670)

Oh, that is documented.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471268659@github.com>

Yee Cheng Chin

unread,
Oct 31, 2025, 12:15:24 AMOct 31
to vim/vim, vim-dev ML, Comment
ychin left a comment (vim/vim#18670)

There are really multiple things going on here, so let me try to break down my thoughts:

The diff algorithm clearly has identified the differing lines and the differences between them as it shows the differing lines and their differences in both windows. However, the lines are not always aligned side-by-side as they should be and as they were before 9.1.1753.

The diff algorithm does not know which line is matched with which, and there is no simple answer for what should be matched with each other. This is because every line has 'csv' changed to 'txt', so technically every line is different. The algorithm can guess (which is what linematch does) but there's a limit to that.

Before 9.1.1753, the default diffopt was "inline:simple". Note that previously it did not align texts side-by-side as @ghgary may have thought. If you take a closer look, this is what it looks like:

image.png (view on web)

Note how the lines are not actually matching? The dates are completely off. It makes you think it's aligning it but the actual matching ones (the 2024-) ones are not actually side-by-side. If you still want the old behavior (which I have to repeat: it doesn't match "matching lines" as you may think), you can set diffopt to use inline:simple.


I've seen numerous instances of this problem before, but this time I had time to investigate and report it. It has existed since 9.1.1753.

Do you have other examples? I suspect if you take a closer look to a lot of them the old behavior was not actually matching up the way you expect them to.

That said, there is a degenerate case that I think could be improved and have been working on. It looks like this:

image.png (view on web)

The second line should ideally be highlighted as an "add" rather than "changed". I don't think it's worth it to dive into the details here, but there are ways to fix it.


I was expecting diff to just work, as it always has, without tweaks. Otherwise, I like the new algorithm in that it's much easier to see multiple differences in a line.

It's difficult to have things "just work" when a diff algorithm does not know the user intent and needs to work in all kinds of situations, and it's hard to infer that unless we have a sophisticated algorithm to auto-set things on and off. No one setting is going to do it for everyone. It's easy to have degenerate cases where it looks like one option is obviously better than the others. And as I mentioned, the old setting was not "just working" either.

For line match itself, I think setting it on by default will lead to more issues (at least as of how it's implemented now):

  1. It breaks multi-line inline highlighting (inline:char / inline:word), as it breaks each diff block into multiple smaller ones. If you are diff'ing texts where texts could move across lines, line match tends to make them worse, not better. It's more designed for strictly line-based inputs like this example. There may be ways to make inline highlighting work better with it, but it's unclear what the "correct" solution is as some people may explicitly want line match to not do multi-line highlight.
  2. Line match's splitting of diff blocks also often times makes diffget and diffput less intuitive. See neovim/neovim#22696.
  3. Performance tuning could be a little tricky. The reason why the setting has a numeric value next to it is that the algorithm is pretty heavy, so if you have a huge diff you probably don't want to activate it. Xdiff is very fast (from testing it's faster than all the other major diff tools I have tried including VSCode, Meld, and more), but I'm not sure what the implications of turning on line match by default is.

I looked at a few diff tools while researching inline highlight's implementations, and different tools handle this type of behaviors differently. For example, Beyond Compare works in a strictly line-based diffing but it does not do multi-line highlight. Meld works in a strictly block-based system and just do inline highlighting similar to what we have without line-match. VSCode is mostly block based and in this example it just refuses to highlight anything by showing the whole thing as changed. I guess my point is that there are certain choices you have to make when choosing how to present the information which may or may not work for a situation. This is why we have linematch available as an option.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471269422@github.com>

Yee Cheng Chin

unread,
Oct 31, 2025, 12:25:39 AMOct 31
to vim/vim, vim-dev ML, Comment
ychin left a comment (vim/vim#18670)

For line match itself, I think setting it on by default will lead to more issues (at least as of how it's implemented now):

  1. It breaks multi-line inline highlighting (inline:char / inline:word), as it breaks each diff block into multiple smaller ones. If you are diff'ing texts where texts could move across lines, line match tends to make them worse, not better. It's more designed for strictly line-based inputs like this example. There may be ways to make inline highlighting work better with it, but it's unclear what the "correct" solution is as some people may explicitly want line match to not do multi-line highlight.

Just to explain this part a bit to provide more context. If you diff Vim commit b32da7d for example, this is what it looks like with the inline:char defaults:

image.png (view on web)

Whereas turning on linematch would split up the diff block into two, breaking inline highlight (it also makes diffget/diffput odd to use):

image.png (view on web)


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471295877@github.com>

Gary Johnson

unread,
Oct 31, 2025, 3:58:49 AMOct 31
to vim/vim, vim-dev ML, Comment
ghgary left a comment (vim/vim#18670)

There are really multiple things going on here, so let me try to break down my thoughts:

The diff algorithm clearly has identified the differing lines and the differences between them as it shows the differing lines and their differences in both windows. However, the lines are not always aligned side-by-side as they should be and as they were before 9.1.1753.

The diff algorithm does not know which line is matched with which, and there is no simple answer for what should be matched with each other. This is because every line has 'csv' changed to 'txt', so technically every line is different. The algorithm can guess (which is what linematch does) but there's a limit to that.

It knows which lines should be matched with which when linematch is large enough, as pointed out above. In my experimentation so far, linematch must be at least as large as the sum of the lines in both buffers. It's just not at all obvious that one must fiddle with the value of linematch to get good results, at least in the cases I've been investigating.

Before 9.1.1753, the default diffopt was "inline:simple". Note that previously it did not align texts side-by-side as @ghgary may have thought. If you take a closer look, this is what it looks like:

[...]

Note how the lines are not actually matching? The dates are completely off. It makes you think it's aligning it but the actual matching ones (the 2024-) ones are not actually side-by-side. If you still want the old behavior (which I have to repeat: it doesn't match "matching lines" as you may think), you can set diffopt to use inline:simple.

I guess I wasn't very clear in my statement. I didn't mean the that old algorithm would properly align the lines in my example files--every line is different. What I meant was that when the old algorithm recognized small-enough differences between lines, it knew to place those lines side-by-side. The new algorithm doesn't seem to know to do that until linematch is large enough, which requires fiddling by the user and hence, does not "just work".

I've seen numerous instances of this problem before, but this time I had time to investigate and report it. It has existed since 9.1.1753.

Do you have other examples? I suspect if you take a closer look to a lot of them the old behavior was not actually matching up the way you expect them to.

Again, I did not misunderstand how the old algorithm matched lines--I did not explain clearly how I was comparing the old and new behavior.

The only other examples I still have can be fixed by increasing linematch, so they may not matter anymore. If I see any oddities that can't be fixed that way, I'll let you know.

I was expecting diff to just work, as it always has, without tweaks. Otherwise, I like the new algorithm in that it's much easier to see multiple differences in a line.

It's difficult to have things "just work" when a diff algorithm does not know the user intent and needs to work in all kinds of situations, and it's hard to infer that unless we have a sophisticated algorithm to auto-set things on and off. No one setting is going to do it for everyone. It's easy to have degenerate cases where it looks like one option is obviously better than the others. And as I mentioned, the old setting was not "just working" either.

For line match itself, I think setting it on by default will lead to more issues (at least as of how it's implemented now):

[...]

Are you sure it's not on by default now? With the files I've been comparing over the last day, I can't see any difference in the diff display between 'diffopt' not containing linematch at all (the default) and with linematch set to a small value, e.g., smaller than the sum of the number of lines in both files.

Thanks for the explanations.

I now have linematch set to 300, which has fixed the problems I've seen so far. Is there any reason other than performance to limit the value of linematch?


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3471700002@github.com>

Yee Cheng Chin

unread,
Nov 1, 2025, 8:08:34 PMNov 1
to vim/vim, vim-dev ML, Comment
ychin left a comment (vim/vim#18670)

What I meant was that when the old algorithm recognized small-enough differences between lines, it knew to place those lines side-by-side. The new algorithm doesn't seem to know to do that until linematch is large enough, which requires fiddling by the user and hence, does not "just work".

No, it did not do that before.

Again, I did not misunderstand how the old algorithm matched lines--I did not explain clearly how I was comparing the old and new behavior.

I think you may be misremembering how the old algorithm works. I don't want to dismiss your concern, but I think you are unhappy with the diff results but misunderstand the cause. Do you have an example so it's easier to talk about the issue if the original example you gave does not suffice? It's hard to discuss about hypothetical diff results.

Are you sure it's not on by default now? With the files I've been comparing over the last day, I can't see any difference in the diff display between 'diffopt' not containing linematch at all (the default) and with linematch set to a small value, e.g., smaller than the sum of the number of lines in both files.

Yes, I'm sure. You don't see a difference there because a line match with a small value just means line match doesn't do anything.

I now have linematch set to 300, which has fixed the problems I've seen so far. Is there any reason other than performance to limit the value of linematch?

I believe I already explained it in the above comment (#18670 (comment)) why I feel that way, under bullet point 1 and 2. My point is turning on line match could also objectively make the diff worse in other situations, and there is no default setting that works for everyone, unless we do some extra tuning (which may again change the behavior which will never be a strict improvement):


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3476982334@github.com>

Balki

unread,
Nov 17, 2025, 11:22:11 PM (5 days ago) Nov 17
to vim/vim, vim-dev ML, Comment
balki left a comment (vim/vim#18670)

Following workaround can help in many cases including for above:

Add below to vimrc

set diffopt+=anchor

def SetDiffAnchor()
    exe $"setlocal diffanchors+={line('.')}"
enddef

nnoremap <silent><Leader>da <ScriptCmd>call SetDiffAnchor()<CR>
  • search for the common line. i.e. /24-04-03
  • run the mapping \da (leader may be different for you)
  • Move the next window and do the same ctrl w w, then n to search, then \da

vim anchor's on the correct line:

image.png (view on web)


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3544961424@github.com>

Yee Cheng Chin

unread,
Nov 17, 2025, 11:40:28 PM (5 days ago) Nov 17
to vim/vim, vim-dev ML, Comment
ychin left a comment (vim/vim#18670)

The above workaround will indeed work. Just to clarify for others, as diff anchors is a new feature: Diff anchors essentially allow you to split and anchor specific lines with each other. You may want to do that if linematch fails to match lines up to your liking, or you have some other reasons for wanting to split up a diff in exactly the way you want. It's even more manual than what the original poster would want (since he was more asking for an "it just works ™" diff configuration) but it does allow you a lot of control in controlling the diff result to show up exactly how you want.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.Message ID: <vim/vim/issues/18670/3545000272@github.com>

Reply all
Reply to author
Forward
0 new messages