81

I'm using vim -d file1 file2 in order to see the differences between them. This works fine, but I want to ignore whitespace changes - they are irrelevant for source code files.

Vim help states that the following command will do the magic:

set diffopt+=iwhite

But unfortunately, this command only adds -b to diff tool command line, and that only ignores trailing whitespaces. The correct command line key for diff should be -w, to ignore all whitespace changes. But I can't find how to modify the diff command line directly from Vim. Of course I can compile a custom diff, or replace diff with diff.sh, but that looks kinda ugly :(.

Is there a better way to modify how Vim interacts with the diff tool for displaying file differences?

ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
grigoryvp
  • 40,413
  • 64
  • 174
  • 277

6 Answers6

43

Update: As of patch 8.1.0393 (2018-09-15), diffopt can be told to ignore all white space:

set diffopt+=iwhiteall

If you want full backwards compatibility, implement like this:

if exists('&diffopt')
  if has("patch-8.1.0393")
    set diffopt+=iwhiteall
  else
    set diffopt+=iwhite
    function DiffW()
      let opt = ""
       if &diffopt =~ "icase"
         let opt = opt . "-i "
       endif
       if &diffopt =~ "iwhite"
         let opt = opt . "-w "
       endif
       silent execute "!diff -a --binary " . opt .
         \ v:fname_in . " " . v:fname_new .  " > " . v:fname_out
       redraw
    endfunction
    set diffexpr=DiffW()
  endif
endif

I borrowed this function from the diffexpr docs, changing -b to -w and adding a redraw command to ensure the screen repaints immediately rather than waiting for the user to hit Enter.

In my related quests to improve vim's diff functionality, I've found patience diff support and I've been meaning to toy with the diffchar plugin.

Adam Katz
  • 14,455
  • 5
  • 68
  • 83
  • 10
    This should be the accepted answer, since it is the only correct one at this time. It's too bad vim doesn't have a simple option to switch between "diff -b", which does little of use, and "diff -w". – farnsy Jul 31 '14 at 20:10
  • 1
    Somehow my `vim` (version 8, Debian Stretch) blinks and shows a blank screen after `:diffupdate`, repainting the correct screen only after a `PageUp` or `PagDown`. Very strange... – DrBeco Jul 05 '17 at 09:28
  • @DrBeco: This isn't the right place to troubleshoot that, but I'd start by seeing if you have that issue with gvim (assuming you have a GUI). If not, maybe try a different terminal emulator or different `$TERM` definition (like "xterm-color" or "xterm-256color" or even just "xterm"). Otherwise, I suggest searching the web and if that doesn't help, searching and then asking in [vi.SE](https://vi.stackexchange.com/). For a workaround, Ctrl+L might work. Maybe also experiment with changing your syntax highlighting. – Adam Katz Jul 05 '17 at 20:50
  • It didn't work in my vimdiff. The result was as if only set diffopt+=iwhite were executed – ka3ak Jan 23 '19 at 08:20
  • @ka3ak – Make sure you can run `diff -a --binary -i -w FILE1 FILE2` from the command line and that it handles white space to your liking. If it does, perhaps try using the absolute path to that `diff` command. If you need further help, you'll be best served by asking a detailed question about it on [vi.SE](https://vi.stackexchange.com/). Comments, especially those lacking in detail, on this sort of site won't get you the kind of help you seek; you need to ask a question. – Adam Katz Jan 23 '19 at 16:31
32

Yes. Set the iwhite option as you did, but additionally, make diffexpr empty.

From the relevant section of the vim docs:

iwhite

Ignore changes in amount of white space. Adds the "-b" flag to the "diff" command if 'diffexpr' is empty. Check the documentation of the "diff" command for what this does exactly. It should ignore adding trailing white space, but not leading white space.

Note also that you can provide a custom diff command line by setting diffexpr. See the discussion on the vimdiff man page, in particular:

The 'diffexpr' option can be set to use something else than the standard "diff" program to compare two files and find the differences.

When 'diffexpr' is empty, Vim uses this command to find the differences between file1 and file2:

diff file1 file2 > outfile
ire_and_curses
  • 68,372
  • 23
  • 116
  • 141
21

Thanks ire, that helped me. I now only need to have this (simpler than what is proposed by Adam K) in my ~/.vimrc :

set diffopt+=iwhite

set diffexpr=""

And it does it... That is still the most powerfull diff tool I know of, far better than any other.

gnat
  • 6,213
  • 108
  • 53
  • 73
greg
  • 227
  • 2
  • 2
  • 7
    No, this implements diff -b, not diff -w as the question requests. Adam K has the only correct answer here. – farnsy Jul 31 '14 at 20:08
  • Thanks! Just "set diffopt+=iwhite" is already useful, because it be issued from vimdiff itself, interactively. – Alexey Polonsky Oct 02 '17 at 07:35
11

I know it's an antique question but for others like me who didn't know, this is now available:

:set diffopt+=iwhiteall

Adds the "-w" flag to the "diff" command if 'diffexpr' is empty.

See :h 'diffopt'

Kieran
  • 506
  • 6
  • 6
  • The `+=` operator simply adds to existing content regardless of whether it was empty (see [`:help +=`](https://vimdoc.sourceforge.net/htmldoc/eval.html#:let+=)). It does not require the value to be empty beforehand. I don't think vim has an operator like `||=`, so the logic as you describe it would have to be `if (&diffopt == "") | set diffopt=iwhiteall | endif` – Adam Katz Aug 02 '23 at 17:08
2

For those hitting "Invalid argument" doing set diffopt+=iwhite, try without the + like so:

set diffopt=iwhite

However, a more robust approach would be to set ignore whitespace while preserving existing options. Beware though, that the "Invalid argument" error is likely caused by one of those existing options not being supported. In my case it was the "internal" option therefore I needed to set options in the following order:

set diffopt-=internal
set diffopt+=iwhite

Or add the following to your .vimrc:

if &diff
    set diffopt-=internal
    set diffopt+=iwhite
endif

Credit to https://www.micahsmith.com/blog/2019/11/fixing-vim-invalid-argument-diffopt-iwhite/

user3325776
  • 105
  • 2
  • 10
0

Addressing an issue brought up in the comments of Adam Katz's solution:

Depending on the vim version and setup of the user, a silent command can neglect to redraw the screen after it is issued. I also encountered this problem, which arose whenever I executed :diffo after using the suggested diffexpr. My solution was to change the silent execute command to the following:

silent execute "!diff -a --binary " . opt .
 \ v:fname_in . " " . v:fname_new .  " > " . v:fname_out | redraw!

This forces a redraw after the command is issued.

Brian Pollack
  • 198
  • 3
  • 12