Wikia

Vim Tips Wiki

Running diff

Talk0
1,613pages on
this wiki
Revision as of 17:20, February 28, 2009 by Fritzophrenic (Talk | contribs)

Tip 416 Printable Monobook Previous Next

created January 31, 2003 · complexity basic · author Juan M. Medina · version 6.0


I read a couple postings of people having this issue, even if they have a diff program in their path when running on Windows platforms.

Check out your _vimrc file, function "MyDiff". If the path to the diff file contains ANY spaces, enclose the path in double quotes. Alternatively you can remove the path and just leave the diff file and check.

This is the line that if fixed in my _vimrc:

Changed

silent execute '!C:\Program Files\Vim\vim61\diff -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out

To be:

silent execute '!"C:\Program Files\Vim\vim61\diff" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out

I am running the diff program that comes with CygWin and it works just fine.

Also see http://vim.wikia.com/wiki/Fix_errors_that_relate_to_reading_or_creating_files_in_the_temp_or_tmp_environment_on_an_MS_Windows_PC

Comments

The instructions make a lot more sense when you find this example in the documentation:

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 "!diff -a --binary " . opt . v:fname_in . " " . v:fname_new .
  \  " > " . v:fname_out
endfunction

To correct E97 I found that I had to add double quotes around the entire command, like so:

silent execute '!""C:\Program Files\vim\vim62\diff.exe" -a ' . opt . '"' . v:fname_in . '" "' . v:fname_new . '" > "' . v:fname_out . '""'

I am running gvim 6.2 on a Win2000 Server. My shell command, "cmd.exe /c", was stripping the double quotes around Program Files and causing the execution to fail.


I'm running gvim 6.1 on Windows 2000, not the OS of my choice.

My problem was as simple as diff.exe not being in the PATH.

I added a diff.bat to my "bin" directory that was in the path and it solved it:

@"C:\Program Files\Vim\vim61\diff.exe" %*

I couldn't find MyDiff in my _vimrc. Perhaps I had an old _vimrc.


The solution that I found was to modify the default line in the _vimrc and double up the backslashes:

silent execute '!C:\\Vim\\vim62\\diff -a ' . opt . '"' . v:fname_in . '" "' . v:fname_new . '" > "' . v:fname_out . '"'

Since I knew I didn't have spaces in my path, I knew that wasn't the problem.

But a good way to find out what is causing the problem for you in each different case, the solution is fairly straightforward: remove the "silent" at the beginning of the line. This will let you see the execution of the command and the more detailed error messages returned from the diff call. That's how I figured mine out, since the output said:

C:/mks/mksnt/sh.exe -c "C:\Vim\vim62\diff -a "..." "..." > "...""
C:Vimvim62diff: not found
shell returned 127

That "C:Vimvim62diff" gave it away. You'll probably find useful info in this same output.


Well, the remove silent was the key for me. It let me find the problem anyway.

On Windows XP, the error reported that C:\Program is not recognized as an internal or external command, operable program or batch file.

I'm using Microsoft Windows XP [Version 5.1.2600].

I removed the reference to path as I had added the c:\program files\vim\vim62 to my path environment variable

_vimrc line in my file = silent execute '!diff -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out


Adding the path to cygwin's diff worked for me.


I changed the path to use forward slashes and changed Program Files to Progra~1, stripped out the extra double quotes, and it started working.


I just copied diff.exe into my C:/winnnt/system32 folder and changed the line to just be diff -a. Worked like a charm.


There's no general solution to fix this problem out-of-the-box. It depends on the idiosincrasies of the command processor (shell) that is used to "silent execute" the line. For instance, on my winxp box I usually start gvim from a 4nt.exe command line, which in turn sets COMSPEC to be 4nt.exe instead of the default cmd.exe. So, in my case, the simplest way to fix MyDiff is to change it this way:

silent execute '!C:\Progra~1\vim\vim63\diff -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out

which runs: 4nt.exe /c c:\Progra~1\vim\vim63\diff -a ...

Perhaps MyDiff out-of-the-box could be made more robust if it used the short filename (no blanks) form instead of attempting to quote spaces. I don't know what to do with backward or forward slashes, though. If cygwin bash is used, I think it requires forward slashes, while 4nt needs backward slashes.


I am running Vim 6.3 on Windows 2000. I copied diff.exe from cygwin to c:\WINNT\system32 and that fixed the problem, without changing anything else.

I removed diff.exe from c:\WINNT\system32 and added c:\cygwin\bin to the windows path environment variable, and that also worked.

I installed gvim for windows frimthe vim.org download, and there was not diff.exe included in the distribution. There was no MyDiff function to be found, except in the documentation. There was no 'silent execute' call to be found in any file either - not in _vimrc, or anywhere else in the distribution. The distribution I downloaded and installed was version 6.3, the non-ole version, and the runtime files as well. I installed everything in C:\Program Files, where unzipping everything to that destination put the distribution in C:\Program Files\vim\vim63, and C:\Program Files\vim\vimfiles. Hopefully this will help vim63 users. Just to satisfy my curiousity, did I do something dramatically wronge, that there was not Mydiff() function, no "silent execute" calls, and no idff.exe file?


Just do what is in the Documentation . Read and follow directions how hard is that!


I tried all of the suggestions in this thread but they didn't work for me. I finally determined my problem was due to the fact I could not write temp files to the locaton the shell (cmd.exe) wanted to write them. My (Windows) desktop has policies forced upon it from the network.

The error messages (*e97* and *e485*) and the "verbose" setting helped me to make this determination.

To correct my problem I was able to change the "TMP" / "TEMP" variable to a different location (not my profile's location) and the diff command (as well as other commands such as grep) began to work.

So if the suggestions in this thread aren't working for you, try to change your "TMP" / "TEMP" variables.


I spent a lot of time to get this to work, mostly because I work in an unsual environment: Windows 2000, bash.exe (from http://www.steve.org.uk/Software/bash/) with the UnixUtils (from http://unxutils.sourceforge.net/). The main advantage is that I can work very Unix-like, without a complete cygwin installation.

However, I hat to "set shell=bash.exe" in my _vimrc file to get it working. Note that bash.exe must be in the PATH, of course.


I found where diff.exe was located. On my system, it is at: C:\Program Files\vim\vim61 I just added that to the Path in the system environment variables. Works fine now.

The suggestions that moved a copy of the diff.exe to other locations are doing the same thing. Just moving diff.exe to a place the operating system can find it.


After trying most of the solutions above, I can now create diffs. Adding the location of the diff command to my path did not work. I could create diffs from a Windows cmd shell, and I could create them from gvim if I started gvim from a cmd shell, but I could not create them if I started gvim from the RMB (right mouse button context menu). The solution was found by removing the "silent" entry from the _vimrc as suggested above, and then working thru the error messages. My final entries are:

if &sh =~ '\<cmd'
  silent execute '!""C:\Program Files\Vim\vim63\diff" ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3 . '"'
else
  silent execute '!C:/Progra~1/Vim/vim63/diff ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3
endif

Thanks to all of the others who have contributed.


The hint with the shell fixed my problem. The "execute" used the wrong program, not the cmd.exe.

In _vimrc create the following line:

set shell=cmd.exe

I got the following error when i tried to use diff in gvim 6.3

E10: \ should be followed by /, ? or &
E97: Cannot create diffs

I had changed the following :

oldfile - silent execute '\"!D:\Program Files\vim\vim63\diff\" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out
newfile - silent execute '!"D:\Program Files\vim\vim63\diff" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out

And the problem was resolved


I just upgraded from 6.3 to 6.4 and had this problem because the path to gvim.exe and the packaged diff.exe changed. To make it more forwards compatible, I changed the "silent execute" line to this:

silent execute '!"'.$VIMRUNTIME.'\diff" ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3

It works for me, but I don't have any spaces or odd characters in my $VIMRUNTIME directory (C:\vim\vim64\), so give it a test. My goal is to have one line that will work no matter what your vim install directory is named, without having to alter your PATH variable, so long as there is a diff installed in the same directory as vim and gvim. I also never had any problem with backslashes, nor do I have them now, but the double quotes before and after $VIMRUNTIME should at least take care of issues with spaces.


I suggest using forward slashes. You might want to change the following line in your default _vimrc:

Change: C:/Vim/vim63 to where vim lives on your system : (if you dont know where, do this in VIM :echo $VIMRUNTIME )

[old]

"silent execute '!"C:\Vim\vim63\diff.exe" ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3

[new]

silent execute '!"C:/Vim/vim63/diff.exe" ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3

Perhaps adding " " as safety, is always good advice. For my example, there are no spaces in dir names, so you don't need the "".


This seems to work (Win XP SP2). All I'm doing is double-double quotes around the

C:\Program Files\Vim\vim64\diff

part.

Hint: Leave out 'silent' until you sort the error out.

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 '!""C:\Program Files\Vim\vim64\diff"" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out
endfunction
endif

Bug in gvim distribution from Cream

  • JB note: I have rewritten this bug report (and confirmed it) because it is a good description of probably what is the fundamental problem experienced by all the confused users. Later, I'll try to merge the different accounts, and should probably ask Steve Hall for advice.

Where to download Vim mentions that Cream's "standard" Vim is a good place to download a fully patched installation of Vim and gvim for Windows (using the "Windows Vim installers without Cream" choice). However, versions upto 7.2.2 (and possibly later) have a bug in the way that diff is installed.

By default, the install creates directory C:\Program Files\vim which contains only files README_lang.txt and _vimrc, and folder vim72 which contains the Vim files, including gvim.exe, as well as GNU Win32 diff.exe (of course, the directory is vim72 for version 7.2, or something different for other versions).

The _vimrc file has contents:

set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin

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 '\"!C:\Program Files\vim\diff\" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out
endfunction

The bug appears when an attempt to use diff is made (in gvim for example, with the File menu, "Split Diff with"). The following error occurs:

Error detected while processing function MyDiff:
line    4:
E10: \ should be followed by /, ? or &

After editing _vimrc to fix this error, a second error occurs:

E97: Cannot create diffs

The fix is to edit _vimrc to change line 4 of MyDiff by removing the backslash before the double quotes, and by moving the bang (!) so it is before the quoted path, and by changing the path to the location where diff.exe occurs. In the following, "silent" was also omitted so the command is shown when executed. The final correct line 4 is:

execute '!"C:\Program Files\vim\vim72\diff" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out

Or even better, to remain compatible when you upgrade Vim:

execute '!"'.$VIMRUNTIME.'\diff" -a ' . opt . v:fname_in . ' ' . v:fname_new . ' > ' . v:fname_out

After this change (and restarting Vim), diff works correctly.


When I type ':set diffexpr' I see that it is empty, and I use a diff.exe that is in my path, and it all works.

Merge in of all useful info from 678

Windows users should get GnuWin32 diff which is a necessity for serious work.

If errors prevent diff from running, use the verbose option to see how diff is called. For example:

vim -V -od file1 file2

To get diff to work under Windows XP I just had to add another pair of double quotes around the diff command in vimrc inside the MyDiff() function. So, an extra one just before the C of the C: drive and at the end of the string. In my case, the result was:

silent execute '!""C:\Program Files\vim\vim62\diff" -a ' . opt . '"' . v:fname_in . '" "' . v:fname_new . '" > "' . v:fname_out . '""'

If you are not using the traditional GUI diff, you may get the "E97: Cannot create diffs" error due to options that your diff does not understand. For example, entering the command :set diffopt? may display:

diffopt=filler,context:2,icase,iwhite

The diff supplied with Windows SFU 3.5 (Services for Unix) fails if given the icase option. For example, you may want only :set diffopt=filler,context:2,iwhite in your vimrc.

Merge in of all useful info from 715

Some people like to spend time vertically aligning variables and comments by adding or removing whitespace. However, those trivial changes may clutter the output from diff when you later compare the old and new files to check your changes. To ignore whitespace in the diff, enter the command:

set diffopt+=iwhite

You can issue this command while viewing a diff (you may also need :windo diffupdate to update the display), or you can add the command to your vimrc so it is always in effect. :help 'diffopt'


Around Wikia's network

Random Wiki