1 of 2

What does autoread do?

To answer this question, we must first understand what the autoread option does, and more importantly, what it doesn't do.

Unfortunately :help 'autoread' 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:

  • :checktime is used;
  • a buffer is entered;
  • :diffupdate is used;
  • :e is issued for a file that already has a buffer;
  • executing an external command with !;
  • returning to the foreground (^Z, 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 buf_check_timestamp(), check_timestamps() functions, and locations where need_check_timestamps is set to TRUE.

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 +python or +python3 in :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 :checktime.

If you use vim, you will usually have to set a servername yourself if you start Vim:

vim --servername autoread

If you use gvim, a servername is usually auto-assigned in the form of GVIM1 if started as gvim, or VIM1 if started as vim -g. The number is incremented for every gvim instance. You can get the servername (if any) with :echo v:servername.

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

Afterword

There are actually more methods, for example you could use a tool such as entr or the Python inotify or 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 Thread) 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?)