Can't run Vimdiff (7.4) on Windows 7

29

9

I recently installed the 7.4 version of gVim on a Windows 7 machine. Trying to diff two files from the context-sensitive menu on Windows Explorer, I keep getting the error messages:

E810: Cannot read or write temp files
E97: Cannot create diffs

The two selected files are opened in the two-pane gVim view, and the editor seems to be in diff mode, but the actual differences are not highlighted.

The %TEMP% and %TMP% environment variables are populated with a valid directory name.

I get the same response when opening the files in a regular gVim session and typing :diffthis in the command prompt.

This used to work properly with Vim 7.3, but it looked like something was changed in v7.4.

How can I diff the two files?

ysap

Posted 2014-01-06T21:59:27.897

Reputation: 2 116

Answers

45

This issue can be caused by the default _vimrc file created by the installer on Windows. If you're still using that default file, or if you copied it at some point, then check the function you've assigned to the diffexpr option. One of the patches between Vim 7.3 and 7.4 introduced new default quoting rules for the cmd.exe shell on Windows. This patch broke the workaround in the MyDiff() function designed to fix the same issue solved by the patch.

The MyDiff() function was fixed by version 7.4.103 by fixing the installer. Here is the MyDiff() function which the latest installer will create for you if you just want to copy it to your _vimrc:

 function MyDiff()
   let opt = '-a --binary '
   if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif
   if &diffopt =~ 'iwhite' | let opt = opt . '-b ' | endif
   let arg1 = v:fname_in
   if arg1 =~ ' ' | let arg1 = '"' . arg1 . '"' | endif
   let arg2 = v:fname_new
   if arg2 =~ ' ' | let arg2 = '"' . arg2 . '"' | endif
   let arg3 = v:fname_out
   if arg3 =~ ' ' | let arg3 = '"' . arg3 . '"' | endif
   if $VIMRUNTIME =~ ' '
     if &sh =~ '\<cmd'
       if empty(&shellxquote)
         let l:shxq_sav = ''
         set shellxquote&
       endif
       let cmd = '"' . $VIMRUNTIME . '\diff"'
     else
       let cmd = substitute($VIMRUNTIME, ' ', '" ', '') . '\diff"'
     endif
   else
     let cmd = $VIMRUNTIME . '\diff'
   endif
   silent execute '!' . cmd . ' ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3
   if exists('l:shxq_sav')
     let &shellxquote=l:shxq_sav
   endif
 endfunction

You can see your full version in Vim using the :version or :intro commands, or at the splash screen at startup.

Unfortunately if you want an official installer, you will either need to wait until 8.0, or install a nightly build. Nevertheless, you can install Vim from other places or build your own Vim.


Duplicated on Stack Overflow (unusually, on-topic on both sites), if this answer is updated so should the other.

Ben

Posted 2014-01-06T21:59:27.897

Reputation: 2 050

I put the MyDiff() and set diffexpr=MyDiff() in my .vimrc, and I still get the error. I am using Git for Windows' vim/vimdif (:version gives 7.4, patches: 1-872). Am I missing a step? – Captain Man – 2015-10-02T20:11:08.217

Another cause for diff errors is a TMP or TEMP directory that does not exist. Echo the value of $TMP and $TEMP in Vim, do they point to writeable, existing locations? – Ben – 2015-10-02T21:15:25.170

@Ben that is where things got a little odd. :echo $TMP and :echo $TEMP were both /tmp. After doing cd /tmp in git bash and doing ls to investigate, it turns out it's mapped to C:\Windows\Temp, I right-clicked and made the folder not read-only but I still seem to get this issue. I looked at the folder again and it seems Windows made it read-only again, why, I don't know, but it seems to set it back everytime. I need to figure out a way to have it always not be read-only or to map this /tmp to a different folder. – Captain Man – 2015-10-05T15:08:05.133

@Ben setting them to /c/temp and running cacls C:\temp /E /G everyone:F (which as I understand should give everyone full access) still results in the same errors. (I also tried it on C:\Windows\Temp as suggested here).

– Captain Man – 2015-10-05T15:45:00.160

Does C:\Temp exist on your system? It doesn't by default in windows these days. I don't expect anything in C:\Windows to ever work; those folders always need admin rights to access for good reasons, I can't imagine who thought that was a good TMP location. What is your shell set to? The diffexpr here is really designed for a standard cmd.exe setup. – Ben – 2015-10-05T17:11:31.583

1@Ben I've fixed the issue, it was something else causing this, and I misunderstood this MyDiff() to be something to use when using vim on windows, but it's for something for using vim through cmd, I am using vim through git bash. Thank you. – Captain Man – 2015-10-05T18:55:17.347

If it's likely to hit others, feel free to add another answer. There is a spot in the MyDiff function for other shells, but I'm not sure how well it works. – Ben – 2015-10-05T19:50:40.697

Just found out that the suggested fix (which works great for a couple of years now, being migrated between systems) fails when trying to vimdiff from Cygwin terminal. Apparently, the block if takes a wrong branch b/c it misidentifies the command shell. – ysap – 2016-06-28T15:54:41.953

The reported &sh is /bin/bash rather than cmd.exe, but the actual shell is, of course, cmd.exe, so the quoting scheme fails. – ysap – 2016-06-28T16:00:26.843

I don't think I follow you correctly. If you are running Vim in cygwin, with the shell set to cygwin bash, why do you expect to use cmd.exe quoting rules? – Ben – 2016-06-29T02:32:00.707

Ben, I am not expecting anything... just reporting what I see. Since posting that comment I figured out that there are actually two problematic cases - one is using Git's difftool to view file diffs (in which case it uses the bash shell from the Git installation) and the second is when running gvim -d from the Cygwin bash command line. – ysap – 2016-06-29T22:17:20.523

In the MyDiff() function you posted, I removed the silent so I get to see the actual command line. The Git command generates: C:/Program Files (x86)/Git/bin/bash -c "c:\Program" Files (x86)\Vim\vim74\diff" -a --binary C:/cygwin64/tmp/VIoEA21.tmp C:/cygwin64/tmp/VInEA22.tmp > C:/cygwin64/tmp/VIdEA23.tmp". – ysap – 2016-06-29T22:20:14.257

The Cygwin command gave: /bin/bash -c ""C:\Program Files (x86)\Vim\vim74\diff" -a --binary C:/cygwin64/tmp/VIo6893.tmp C:/cygwin64/tmp/VIn6894.tmp > C:/cygwin64/tmp/VId6895.tmp". You can see that the generated commands are different, and the quotes are set in the wrong place. – ysap – 2016-06-29T22:22:36.797

Anyway, I played a little (not so little actually...) with the function, but could not make it to work. I got it to generate the following command: /bin/bash -c "C:/Program\ Files\ \(x86\)/Vim/vim74/diff -a --binary C:/cygwin64/tmp/VIo6C5B.tmp C:/cygwin64/tmp/VIn6C5C.tmp > C:/cygwin64/tmp/VId6C5D.tmp" but from some unidentified reason, it still does not open the editor as expected. However, when using the same line manually from the bash command line - it actually works. So, the problem lies in the gvim -d step. – ysap – 2016-06-29T22:23:17.317

I don't know enough about Vim in cygwin to address that very well. I do know that cygwin has a Vim package available that will natively understand cygdrive paths and such. I also am pretty sure the normal Windows Vim can probably work with the cygwin shell and tools, but you will need to carefully configure all the shell-related options, in particular shellquote and shellxquote. Getting that configuration figured out is probably worth another answer in its own right. – Ben – 2016-07-06T04:15:43.240

cygwin/vim has very FEW features compiled in, so it is best to take the official build of gvim for windows will all the features turned on and tested. If you are using cygwin64, set shell=c:/cygwin64/bin/bash to address the above problem, it affects all plugins that launch shell commands like fugitive.vim also. – mosh – 2017-05-29T06:23:46.670

1Found a few solutions on then net, but this is the only one that worked for me! – ysap – 2014-01-07T18:43:25.547

BTW - how can you tell the # of the sub-version (e.g. 7.4.103)? – ysap – 2014-01-07T21:56:32.753

Three ways: startup on an empty buffer shows version information including patch level, the :intro command shows the same text, and the :version command gives the information on an "included patches" line. :version also gives a very detailed list of included or excluded features as well. – Ben – 2014-01-07T23:50:57.357

1

Also, Bram doesn't usually release any official installers after the initial minor version, e.g. 7.4.0. But there are plenty of places to get an installer for a more recent Vim if you don't feel like compiling, the most often cited probably being here: http://sourceforge.net/projects/cream/files/Vim/

– Ben – 2014-01-07T23:52:56.880

Well, the startup screen and :intro show me the same info (that is, just "7.4"). :version shows "7.4" and elaborates on the compilation time. No patch version number. Your 2nd comment may explain why it is so. It is compiled by mool(at)tororo, which I assume refers to Mr. Moolner. – ysap – 2014-01-08T14:58:29.960

Yes, if no patch level is listed, you have 7.4.0. – Ben – 2014-01-08T17:03:18.403