2

In my daily work, I only deal with unified diffs, so I would like to define the alias

alias diff='diff -puN'

in my .zshrc.

This alias is not respected when I use the shell from the vim command line mode, i.e., when I enter :!diff file1 file2. I believe this is because vim does not invoke an interactive shell.

Thus, I moved the alias from .zshrc to .zshenv which allows me to get plain old unified diffs from within vim (I usually prefer this output over vimdiff's).

On the other hand, doing this breaks vimdiff which apparently is unable to parse unified diffs (It spawns Error E97, but neither its explanation in help E97 nor the references seem to be useful to me: either they seem unrelated (e.g. the shell option) or are above my head (the diffexpr option).

How should I go about having both vimdiff and my alias for diff work at the same time?

Simon K.
  • 23
  • 2
  • Aliases should be used for interactive use only. You may want to try defining a shell function instead of an alias for your `diff` definition in your shell profile. – Janis Apr 22 '15 at 10:19
  • [Vim is working on enabling unified diffs](https://github.com/vim/vim/pull/8197), so this issue should disappear soon. – gregorias May 18 '21 at 19:27

1 Answers1

1

Changing the semantics of the diff command indeed wreaks havoc on Vim (this is explained under :help diff-diffexpr: The output of "diff" must be a normal "ed" style diff. Do NOT use a context diff.), and potentially other programs, too.

A pure shell alias with the same name is fine, as that is only considered when you type commands interactively (or in shell functions, which you should have few of). If you need a changed diff command for non-interactive use (e.g. in Vim's :! command), better define a shell wrapper script / exported shell function / alias in .zshenv under a different name, e.g. diffu.


If you really want to stick to an identical, exported alias (despite the risks of breaking programs), you have to reconfigure Vim so that it doesn't use it. Unfortunately, there's no simple option for the diff executable; you have to write an entire custom 'diffexpr'. Fortunately, there's an example for that under :help diff-diffexpr that emulates the default one. You just need a tiny change to make it avoid your diff alias, e.g. by specifying the full path to diff.

set diffexpr=MyDiff()
function MyDiff()
   let opt = ""
   if &diffopt =~ "icase"
     let opt = opt . "-i "
   endif
   if &diffopt =~ "iwhite"
     let opt = opt . "-b "
   endif
   silent execute "!/usr/bin/diff -a --binary " . opt . v:fname_in . " " . v:fname_new .
    \  " > " . v:fname_out
endfunction
Ingo Karkat
  • 11,664
  • 1
  • 34
  • 48
  • Thank you. I feared that the answer might look like yours... The solution in your second paragraph looks like the sanest choice and I'll probably opt for that one. I appreciate your taking the time for fleshing out the solution in the second part - which looks a bit too complicated for what it is supposed to do (I was also put off by the parenthetical *this does almost the same as `'diffexpr'` being empty* in the help page). – Simon K. Apr 22 '15 at 11:03