30

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?

Peter Mortensen
  • 12,090
  • 23
  • 70
  • 90
ysap
  • 2,620
  • 12
  • 50
  • 74

1 Answers1

47

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
  • 2,249
  • 19
  • 19
  • 1
    Found a few solutions on then net, but this is the only one that worked for me! – ysap Jan 07 '14 at 18:43
  • BTW - how can you tell the # of the sub-version (e.g. 7.4.103)? – ysap Jan 07 '14 at 21:56
  • 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 Jan 07 '14 at 23:50
  • 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 Jan 07 '14 at 23:52
  • 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 Jan 08 '14 at 14:58
  • Yes, if no patch level is listed, you have 7.4.0. – Ben Jan 08 '14 at 17:03
  • 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 Oct 02 '15 at 20:11
  • 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 Oct 02 '15 at 21:15
  • @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 Oct 05 '15 at 15:08
  • @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](http://answers.microsoft.com/en-us/windows/forum/windows_xp-security/user-profile-does-not-permit-writing-to/6d107e09-9127-4255-a8b0-1c76a0be9683?auth=1)). – Captain Man Oct 05 '15 at 15:45
  • 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 Oct 05 '15 at 17:11
  • 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 Oct 05 '15 at 18:55
  • 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 Oct 05 '15 at 19:50
  • 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 Jun 28 '16 at 15:54
  • 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 Jun 28 '16 at 16:00
  • 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 Jun 29 '16 at 02:32
  • 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 Jun 29 '16 at 22:17
  • 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 Jun 29 '16 at 22:20
  • 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 Jun 29 '16 at 22:22
  • 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 Jun 29 '16 at 22:23
  • 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 Jul 06 '16 at 04:15
  • 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 May 29 '17 at 06:23