Vimdiff failing with "Cannot read or write temp files" - vim

I'm using Vim 7.4 on Windows 7.
I do have a custom _vimrc file, but both Vim and gVim work fine. When I try to run vimdiff .\xxxxx .\yyyyy, it gives the error
Cannot read or write temp files

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.
The official Vim 8.0 installer is now available, or you can install a nightly build, install Vim from other places or build your own Vim. Installing with any of these methods should get you the latest default vimrc file if you want to grab the latest incarnation of this function.
Copied from my answer to this same question on Super User.

Adding:
set shell=c:\cygwin64\bin\bash.exe
to my _vimrc worked for me.

I was getting this exact error and had uselessly fiddled around with the permissions on set backupdir.
But then I remembered that I have recently changed to Windows 7 and to using Cygwin 64 and had forgotten to repoint the following setting.
set shell=c:\\cygwin64\\bin\\zsh.exe shellcmdflag=-c shellxquote=\"
And hey presto the error went away and the following now works:
gvim -d v1.php v2.php
So what this error is really saying is I can't find your shell or cmd!

I installed Vim 8.0 on Windows 7. After adding the directory containg vim to my PATH variable "diffthis" etc. worked out of the box if called from a CMD command line. But calling gvim from a cygwin bash resulted in error "E97: cannot create diff".
The following _vimrc (inspired by this and this post) solved the problem with cygwin and it also works with Windows commandline:
runtime vimrc_example.vim
" Change path to bash with your workstation specific path
set shell=C:\Programme\cygwin\bin\bash
" Override value of TMP from cygwin (normally set to /tmp)
let $TMP="c:/tmp"
Note that with the _vimrc above you lose gvim's Windows-specific behavior like using CTRL-V for pasting etc (you can use SHIFT-Ins anyhow). But with enabled Windows-specific behavior (like in the generated _vimrc during install) gvim failed to perform "diffthis" with "E97:..." error.

I also was getting the messages
E810: Cannot read or write temp files
E97: Cannot create diffs
However my _vimrc file was fine.
The issue was that C:\Program Files\Vim\vim74 was not in the PATH environment variable, so Vim could not launch diff.exe.

Vim 8.1
I was experiencing this issue, and this answer resolved it for me.
Add this to your ~/.vimrc
set shell=$COMSPEC
For me using git for windows, this value is: C:\WINDOWS\system32\cmd.exe
Also note that in this thread every answer other than the top answer relates to changing your shell variable. So if you're someone who has stumbled upon this answer, try taking a look at that.

Have you set vim shell to powershell? If so this answer might work. After hard searching my problem was solved by it.
At least see what shell you're using, or try to set vim shell to other shells if installed, e.g. set shell=/path/to/bash.exe, it might shed some light.

Related

How can I source files relative to file?

I'm trying to split my vimrc up into multiple files - init.vim, keybindings.vim, ui.vim, etc. - but I can't get Vim to source files relative to init.vim (it instead sources relative to where I launch Vim from.
This is what I've got at the top of init.vim:
source keybindings.vim
source ui.vim
If I run vim from the same directory as those files, it works fine; if I run it from any other directory, I get the following errors:
Error detected while processing /path/to/vimrc:
line 1:
E484: Can't open file keybindings.vim
line 2:
E484: Can't open file ui.vim
Press ENTER or type command to continue
Edit: It's worth noting that I'm using NixOS, so I don't know what the absolute paths will be, nor if they would be constant if I found out.
I think you can use
runtime keybindings.vim
Source needs the full path, you can however simplify it using something like this :
let path = expand('%:p:h')
exec 'source' path . '/keybindings.vim'
You can have a look at mine here - https://github.com/dhruvasagar/dotfiles/blob/master/vim/vimrc for reference.
If the order is not important, you can just put your scripts into ~/.vim/plugin/, and they will be sourced after ~/.vimrc. You can check :scriptnames output to see what gets sourced when.
You can influence the ordering somewhat via the plugin filenames. For example, I have a ~/.vim/plugin/00plugin-configuration.vim that configures Vim plugins; the 00... ensures this is sourced first.
To get finer control, I would instead put the scripts into ~/.vim/. Vim will ignore them there, but they can easily be addressed via :runtime, which looks in all runtimepaths, and ~/.vim/ typically is included in 'runtimepath':
# .vimrc
runtime init.vim
runtime keybindings.vim
...
Relevant help pages: :help .vimrc and :help load-plugins.
Building on Dhruva's answer, you can make a function to help out with this
function! SourceLocal(relativePath)
let root = expand('%:p:h')
let fullPath = root . '/'. a:relativePath
exec 'source ' . fullPath
endfunction
You then use it like
call SourceLocal ("yourScript.vim")
I have met exactly the same issue with you in Neovim. I split my large init.vim file into several small vim scripts and I want to source them inside init.vim.
This is what I get finally based on #Dhruva Sagar's links:
let g:nvim_config_root = stdpath('config')
let g:config_file_list = ['variables.vim',
\ 'options.vim',
\ 'autocommands.vim',
\ 'mappings.vim',
\ 'plugins.vim',
\ 'ui.vim'
\ ]
for f in g:config_file_list
execute 'source ' . g:nvim_config_root . '/' . f
endfor
As none of the solutions works as a real substitute for source working globally (on any script, even sourced from vimrc), I ended up with this solution and decided to share here, which can be used as a substitute for source with relative support, as simple as:
Rsource /home/me/.vim/your/file/path
Rsource $HOME/.vim/your/file/path
Rsource your/file/path
Rsource ../your/file/path
To use it, this must be defined on your vimrc or any file sourced by it before you can use Rsource:
if !exists('g:RelativeSource')
function! g:RelativeSource(file)
let file = expand(a:file)
" if file is a root path, just source it
if stridx(file, '/') == 0
exec 'source ' . file
return
endif
let sfile = expand('<sfile>:p:h')
" If this is called outside this script, it will contains this script
" name, this function name, a script_marker then the executing script name
" In this case we extract just the last part, the script name which called
" the this function
let script_marker = '..script '
let path_index = strridx(sfile, script_marker)
if path_index == -1
let path_index = 0
else
let path_index += len(script_marker)
endif
let path = strpart(sfile,path_index)
let absolute_path = resolve(path . '/'. file)
exec 'source ' . absolute_path
endfunction
command! -nargs=1 Rsource :call g:RelativeSource(<q-args>)
endif
This is safe to be used in any script or plugin.
These are all great solutions, and this is what I ended up using.
let home = expand('~')
exec 'source' home . '/.config/nvim/prettierConfig.vim'

vimdiff is not working under cywin with mobaxterm (E97 cannot create diffs)

On my PC I am using mobaxterm and installed vim in its cygwin environment.
vim and gvim works fine with no issue.
Only vimdiff is not working as I get the error : "E97: Cannot create diffs"
I installed diffutils "GNU collection of diff" and checked it on 2
files and it works fine.
I have no disk full.
I run vim -d or vimdiff without using my .vimrc and it is the same.
So it is not coming from my vim configuration.
I am using last version of mobaxterm (10.4) and vim v8 but the issue
was the same with previous version (mobaxterm v9 and vim v7.X).
I run vimdiff with -V option and I get :
Calling shell to execute: "diff -a /tmp/vkjIw1o/0 /tmp/vkjIw1o/1 > /tmp/vkjIw1o/2"
/tmp/vkjIw1o/0 /tmp/vkjIw1o/1 > /tmp/vkjIw1o/2"
E97: Cannot create diffs
I can see that /tmp/vkjIw1o is created, no file inside.
This is same case as this very old post https://superuser.com/questions/455210/vimdiff-in-cygwin-is-not-working-properly .
It is annoying I still have this issue.
I hope someone solved this.
JP
More infos :
1) I modified one file (vimrc2). Running this command from vim works fine : :!diff ~/.vimrc ~/vimrc2
## -51,7 +51,7 ##
"
set showmode
set ruler
-set cursorline
+"set cursorline
set number
2) For temp dir, echo tempname() gives me /tmp/vmtID5W/1
Then I can save a file to /tmp with :w /tmp/test.txt
I solved the issue by adding this code in my .virmc file :
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 "!/bin/diff.exe -a --binary " . opt . v:fname_in . " " . v:fname_new . " > " . v:fname_out
endfunction
I took the idea from https://github.com/neovim/neovim/issues/1466
Note that I had to write /bin/diff.exe
Thanks for the help.
I was facing the same problem in MobaXTerm for a long time up to version 11.1. The reason (and solution) I finally found is twofold:
E810 is about Vim being unable to write and read temporary files. If you run fugitive you get E484 about the same.
E97 is about wrong output of the diff executable called by Vim.
Resolving E810 and E484
In my case it was about wrong set shellxquote=\", which I got during my searching for a solution. That setting is responsible for how Vim quotes filenames. Removing it, resulting in unsetting, resolved the error with writing and reading temporary files.
Resolving E97
This is where the diffexpr comes to help. But it might not be sufficient itself. In my case I had to install diffutils package too as the /bin/diff was pointing to busybox, which supports only the unified diff format, while Vim requires ed-style (i.e. normal) diff format.
Now my diff executables are:
lrwxrwxrwx 16 Jan 29 13:26 /bin/diff -> /bin/busybox.exe*
-rwxr-xr-x 201.5K Dec 6 2016 /bin/diff.exe*
-rwxr-xr-x 56.0K Dec 6 2016 /bin/diff3.exe*
The difference in output is:
$ /bin/diff one two
--- one
+++ two
## -1,3 +1,3 ##
no change
-file one
+file two
no change
$ /bin/diff.exe one two
2c2
< file one
---
> file two
All that needs to be done is to point to the proper one in the diffexpr function:
silent execute "!/bin/diff.exe " . opt . v:fname_in . " " . v:fname_new . " > " . v:fname_out
Even the -a --binary options are not required.

How to make Syntastic search for javac config file in project

I'm using Syntastic with vim and I've added external libraries to its classpath (using SyntasticJavacEditClasspath). This creates a file in the current working directory (which was my project folder). This is all fine. However, whenever I restart vim, Syntastic seems to search for the .syntastic_javac_config file in the current working directory only, and the cwd is, of course, randomly whereever I left it in my last operation. So it doesn't find the file and I get a bunch of incorrect import errors. Can Syntastic be told to search the file's parents for the config file? If not, is there a way of using vim where this typically works? (I've only been using vim for a couple of months so I might be clueless.)
According to the official manual, the snippet should solve the problem. Put it in your .vimrc, change the javascript, jscs, etc. to required values
function! FindConfig(prefix, what, where)
let cfg = findfile(a:what, escape(a:where, ' ') . ';')
return cfg !=# '' ? ' ' . a:prefix . ' ' . shellescape(cfg) : ''
endfunction
autocmd FileType javascript let b:syntastic_javascript_jscs_args =
\ get(g:, 'syntastic_javascript_jscs_args', '') .
\ FindConfig('-c', '.jscs', expand('<afile>:p:h', 1))

please help to make it work of vimscript

why I can't set path success.
let s:WORKDIR = getcwd()
set path += ".," . s:WORKDIR . "/**"
echo &path
and the echo result is, my current directory is "/home/myname/example", my expected result is
".,/home/myname/example/**", but what i get is,
.,/usr/include,,
it seems this didn't work in my .vimrc script; please help, thanks.
Your syntax of the :set command is wrong; you should be getting errors, too. The += must not be surrounded by whitespace, and you cannot use an expression on the right-hand side. Better use the :let command; it can also modify Vim options (&optionname), not just variables:
let &path .= ",.," . s:WORKDIR . "/**"

NerdTree copy command in Windows 7

I don't see the menu option for Copy command. Here is the menu that I see on my Windows 7 machine:
NERDTree Menu. Use j/k/enter and the shortcuts indicated
==========================================================
> (a)dd a childnode
(m)ove the curent node
(d)elete the curent node
According to the plugin documentation, the Copy command is not supported on all platforms.
A textual filesystem menu is provided which allows you to create/delete/move file
and directory nodes as well as copy (for supported OSs)
Has anybody managed to get this to work in Windows?
I got it working by installing Gow
choco install -y gow
Then adding this line to vim
let g:NERDTreeCopyCmd= 'cp -r'
Thanks: https://github.com/scrooloose/nerdtree/issues/152
PS: The choco command comes from https://chocolatey.org/
The root cause for the issue is discussed in detail(rather colorfully) in this blog post.(ht romainl).
I managed to find a solution by using the cp.exe shipped with msygit.
Ensure cp.exe is in your path
The cp.exe file can be found in <GIT_HOME>\bin directory. My path didn't not contain the <GIT_HOME>\bin directory. So I copied cp.exe and msys-1.0.dll to a directory in my path.
Set the g:NERDTreeCopyCmd variable
Add the line below to the end of the _vimrc file
let g:NERDTreeCopyCmd= 'cp -r '
Fix the implementation of s:Path.copy function.
Replace the lines 2297-2299 of ~/vimfiles/bundle/nerdtree/plugin/NERD_tree.vim (assuming you used pathogen for managing vim plugins)
Replace the lines 2297-2299
let dest = s:Path.WinToUnixPath(a:dest)
let cmd = g:NERDTreeCopyCmd . " " . escape(self.str(), s:escape_chars) . " " . escape(dest, s:escape_chars)
With the lines below
let dest = a:dest
let cmd = 0
if s:running_windows
let cmd = g:NERDTreeCopyCmd . '"' . self.str() . '" "' . dest . '"'
else
let cmd = g:NERDTreeCopyCmd . " " . escape(self.str(), s:escape_chars) . " " . escape(dest, s:escape_chars)
endif
What I did was I added the following to my vimrc
if (has('win32'))
" let g:NERDTreeCopyCmd= 'copy '
let g:NERDTreeCopyCmd= 'Copy-Item -Recurse '
endif
First one works, but I set it to the second, I think you need that for copying directories properly..
I just tried delete, and that also fails. Guess we need a similar workaround.
EDIT: Sorry, you will have to set your shell to run PowerShell for the second command to work!

Resources