To answer this question, we must first understand what the
does, and more importantly, what it doesn't do.
doesn't have a lot of information on this, it just says "a file has been
detected to have been changed outside of Vim". How does Vim detect that a file is
changed? On certain actions, Vim checks the modification time of the file.
These actions are:
For Vim and gVim this is when:
- a buffer is entered;
:eis issued for a file that already has a buffer;
- executing an external command with
- returning to the foreground (
fg, only if the shell has job control).
For gVim, this is also done when:
- closing the "right-click" menu (either by selecting something, or just by closing it);
- focus is changed (this is what you already noticed);
- closing the file browsers dialog that pops up if you use "file -> open", "file -> save as" from the menu (as well as some other places).
I gathered this information from the Vim source by locating all calls to the
check_timestamps() functions, and locations where
need_check_timestamps is set to
I may have missed some events, but the key thing to remember is that Vim only checks if the file is modified in a very limited set of cirsumstances. It certainly doesn't "poll" the file for changes ever n seconds, which is basically what you're after.
So, for your purpose,
set autoread is not enough.
Method 1: Python
This schedules a Python thread to run in the background, it will run
:checktime every n seconds. If
autoread is enabled, this will reload the
buffer from disk, else it will just warn.
This requires that Vim has
:version. It should work
on all platforms (including Windows).
fun! AutoreadPython() python << EOF import time, vim try: import thread except ImportError: import _thread as thread # Py3 def autoread(): vim.command('checktime') # Run the 'checktime' command vim.command('redraw') # Actually update the display def autoread_loop(): while True: time.sleep(1) autoread() thread.start_new_thread(autoread_loop, ()) EOF endfun
You can start this off by using
:call AutoreadPython(); you can of course do
this in an autocmd; for example:
autocmd *.c call AutoreadPython()
Method 2: using the "remote" clientserver
You can send "remote" commands to a Vim or gVim instance with:
vim --servername SERVER_NAME --remote-send ':checktime<CR>'
This will tell the instance
SERVER_NAME to execute
If you use
vim, you will usually have to set a servername yourself if you
vim --servername autoread
If you use
gvim, a servername is usually auto-assigned in the form of
if started as
VIM1 if started as
vim -g. The number is
incremented for every gvim instance. You can get the servername (if any) with
The following function will start a background shell process to send remote
commands to Vim every n seconds. This is functionally identical to the Python
method, but has the advantage of not requiring
+python. It won't work on
Windows however, (although it can probably be made to run on Windows! I just
don't have a Windows machine handy right now).
fun! AutoreadShell() if v:servername == '' echoerr 'v:servername is empty; we need a servername for this.' endif let l:oldshell = &shell " For maximum compatibility (fish/csh users) let &shell = '/bin/sh' let l:cmd = 'vim --servername ' . v:servername . ' --remote-send ":checktime<CR>" --remote-send ":redraw<CR>"' call system('while :; do sleep 10; ' . l:cmd . '; done &') " Note the & at the end let &shell = l:oldshell endfun
There are actually more methods, for example you could use a tool such as
entr or the Python
gamin module to
monitor a file for changes,
:checktime also checks all buffers if it's not
given any arguments, this could be improved on by only checking a single buffer
or a certain file.
However, this answer is already rather long :-) These method should (hopefully!) work fine for most scenarios, or should be easily adaptable to your scenario.
I have plans to make a plugin out of this, but have no timeframe for this ;-)
PS. I also tried to use Ruby, but unfortunately Ruby threads (using
don't run in the background like Python does, so I wasn't able to get this to
work (perhaps there is another way, though?)