33

Assuming that a file doesn't have unsaved changes in the VIM buffer, I'd like it to reload automatically if the file changes on disk. The most frequent use case for this is when I update the working copy in which the file resides.

How can I achieve this?

  • I think this is what you mean, but my specific use case is when I check out a different git branch or commit, I want vim to reload the file. – Nathan Long Feb 12 '16 at 18:56
32

In your ~/.vimrc:

set autoread
  • 9
    Generally autoread will only trigger after executing an external command. This answer details the solutions. – Tom Hale Aug 1 '17 at 5:12
  • This doesn't work Follow the @TomHale link for a detailed answer that does – JonnyRaa Nov 13 '17 at 10:35
11

This is what worked for me

set autoread                                                                                                                                                                                    
au CursorHold * checktime  

The first line wasn't enough by itself. You can put in you .vimrc

credit to Phan Hai Quang

  • The autocmd shouldn't be necessary--checktime is supposed to run internally at the same time the CursorHold event is triggered. In other words, you're just making Vim do a second checktime. – Heptite Jun 18 '16 at 16:37
  • For me it is necessary. Best solution I've found after lots of research. @Heptite, do you have chapter and verse for your assertion? – Tom Hale Aug 1 '17 at 5:19
  • 1
    @TomHale I've reviewed the Vim docs and it doesn't explicitly say, as far as I can tell, but ":help timestamp" would seem to indicate I'm the one in error, and that Vim only performs the check on specific events, so the autocmd could be necessary to cause it to check more frequently. – Heptite Aug 1 '17 at 16:17
5

Autoread does not work correctly. The following works for me:

You need to first install the script from here.

I got the best results by calling the setup function directly, like so.

let autoreadargs={'autoread':1} 
execute WatchForChanges("*",autoreadargs) 

The reason for this, is that I want to run a ipython/screen/vim setup.

You can easily convert this into an enhanced version of view.

script the process..

mkdir -p ~/bin
cat <<`OUT` > ~/bin/vimviewer
#!/usr/bin/env sh
exec vim -n --cmd "source /home/bryan/.vim/.vimrc.watchforchanges | let autoreadargs={'autoread':1} | execute WatchForChanges('*',autoreadargs)" $@
`OUT`

chmod 755 ~/bin/vimviewer
vimview test.txt
  • 1
    If you're using one of the vim GUIs such as gVim or MacVim then the autoread command integrates fine with the rest of the environment. E.g. editing the file in some other program, another editor or from source control, then switching back to vim will autoread the updated files. The problem seems to be with how the terminal version of vim integrates. The terminal version can't tell when you switch between programs either in the GUI or using terminal multiplexers like tmux, so it fails to autoread at relevant times. It would be nice if vim would just subscribe to relevant file-system events. – bames53 May 3 '14 at 23:31
3

vim-autoread plugin has worked for me so far:

vim-autoread

Automatically causes vim to reload files which have been written on disk but not modified in the buffer since the last write from vim. This enables a file open in vim to be edited using another application and saved. Upon returning to vim, as long as you haven't modified the file since the last change, the file will be automatically updated to reflect the changes made on disk, as though you had pressed :e manually.

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review – Burgi May 5 '17 at 13:34
  • @Burgi I've added plugin description that explains how it solves the problem. – Wojtek Kruszewski May 5 '17 at 14:01
  • I tried it but I have to type a navigation command (like j) to see the effective update. I created an issue here about this: github.com/djoshea/vim-autoread/issues/3 – Martin Delille Dec 19 '18 at 13:34
3

from this answer (refering to an answer by PhanHaiQuang and a comment by @flukus)

One can run this oneliner from ex (whithin vim) when needed (or put each command in vimrc, for when log-files are opened.)

:set autoread | au CursorHold * checktime | call feedkeys("lh")

Explanation:
- autoread: reads the file when changed from the outside (but it doesnt work on its own, there is no internal timer or something like that. It will only read the file when vim does an action, like a command in ex :!
- CursorHold * checktime: when the cursor isn't moved by the user for the time specified in 'updatetime' (which is 4000 miliseconds by default) checktime is executed, which checks for changes from outside the file
- call feedkeys("lh"): the cursor is moved once, right and back left. and then nothing happens (... which means, that CursorHold is triggered, which means we have a loop)

  • lh does not do nothing, if the cursor is at the last position on the line, lh will change its location. – Mahmoud Al-Qudsi Apr 25 '18 at 23:41
  • Exactly, thats the point. The file is reloaded with the minimum of interaction or changes to the file. You could jump to the last or first line if you want (just replace lh with gg or G), but the goal here, is just to reload the file in vim, and thats whats done by this one-liner, nothing more. What Do you like to be done here? – eli Apr 26 '18 at 9:01
  • @MahmoudAl-Qudsi ... meaning, that "lh" just triggers the CursorHold - action (I mentioned that in the Explanation), which then again triggers the autoread – eli Apr 26 '18 at 9:42
1

There are some plugins listed here that might work depending on your version of Vim.

Another approach is to periodically send the checktime command to vim from an external process. Here's a ShellJS script to do this (requires shelljs-plugin-sleep, NeoVim, and nvr)

while (true) {
  sleep(15);
  var servernames = exec('nvr --serverlist').trim().split('\n');
  if (!servernames.length || !servernames[0]) {
    continue;
  }
  servernames.forEach(
    (sn) => exec(`nvr -c "checktime" --servername ${sn}`) );
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.