Can vim monitor realtime changes to a file

Vim

Vim Problem Overview


My question is similar to this [how to monitor a text file in realtime][1] [1]: https://stackoverflow.com/questions/18632/how-to-monitor-a-text-file-in-realtime

but I want to do it in vim. I know I can read an opened file use tail -f sample.xml file, and when new content is written to the file, it'll also write the new content to my screen. Can I have vim automatically fill the new data when a file is updated?

Vim Solutions


Solution 1 - Vim

You can :set autoread so that vim reads the file when it changes. However (depending on your platform), you have to give it focus.

From the help:

> When a file has been detected to have > been changed outside of Vim and it > has not been changed inside of Vim, > automatically read it again. When the > file has been deleted this is not > done.

Solution 2 - Vim

Don't know about automatically, but you can type:

:e!

to reload the file

Solution 3 - Vim

Put the following in your .vimrc:

" check one time after 4s of inactivity in normal mode
set autoread
au CursorHold * checktime

Solution 4 - Vim

like @flukus said in a comment to a previous answer you can call feedkeys["lh"] (it moves the cursor to the right and back to the left, which normaly doesn't do harm when viewing a log file)

So, if you combine the rest of the answer you have a oneliner you can run from ex (whithin vim) when needed:

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


(if you would want to jump (nearly) to the end of the file, just use "G" instead of "lh" with feedkeys)

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)

Additionally you can :set syntax=logtalk to color the log

To stop the scrolling when using call feedkeys("G"), execute :set noautoread - now vim will tell, that the file was change ans ask if one wants to read the changes or not)

(Does this have any sideeffects?)

Edit: I see one side-effect: if one uses "G" as the feedkey, it will scroll down every currently opened buffer?! So, it's not possible to work in the left buffer of a splittet window while having the right buffer scroll down a logfile automatically

Solution 5 - Vim

Stick this in your .vimrc and it should work like a boss. (Taken from: http://vim.wikia.com/wiki/Have_Vim_check_automatically_if_the_file_has_changed_externally)

" Function to Watch for changes if buffer changed on disk
function! WatchForChanges(bufname, ...)
  " Figure out which options are in effect
  if a:bufname == '*'
    let id = 'WatchForChanges'.'AnyBuffer'
    " If you try to do checktime *, you'll get E93: More than one match for * is given
    let bufspec = ''
  else
    if bufnr(a:bufname) == -1
      echoerr "Buffer " . a:bufname . " doesn't exist"
      return
    end
    let id = 'WatchForChanges'.bufnr(a:bufname)
    let bufspec = a:bufname
  end
  if len(a:000) == 0
    let options = {}
  else
    if type(a:1) == type({})
      let options = a:1
    else
      echoerr "Argument must be a Dict"
    end
  end
  let autoread    = has_key(options, 'autoread')    ? options['autoread']    : 0
  let toggle      = has_key(options, 'toggle')      ? options['toggle']      : 0
  let disable     = has_key(options, 'disable')     ? options['disable']     : 0
  let more_events = has_key(options, 'more_events') ? options['more_events'] : 1
  let while_in_this_buffer_only = has_key(options, 'while_in_this_buffer_only') ? options['while_in_this_buffer_only'] : 0
  if while_in_this_buffer_only
    let event_bufspec = a:bufname
  else
    let event_bufspec = '*'
  end
  let reg_saved = @"
  "let autoread_saved = &autoread
  let msg = "\n"
  " Check to see if the autocommand already exists
  redir @"
    silent! exec 'au '.id
  redir END
  let l:defined = (@" !~ 'E216: No such group or event:')
  " If not yet defined...
  if !l:defined
    if l:autoread
      let msg = msg . 'Autoread enabled - '
      if a:bufname == '*'
        set autoread
      else
        setlocal autoread
      end
    end
    silent! exec 'augroup '.id
      if a:bufname != '*'
        "exec "au BufDelete    ".a:bufname . " :silent! au! ".id . " | silent! augroup! ".id
        "exec "au BufDelete    ".a:bufname . " :echomsg 'Removing autocommands for ".id."' | au! ".id . " | augroup! ".id
        exec "au BufDelete    ".a:bufname . " execute 'au! ".id."' | execute 'augroup! ".id."'"
      end
        exec "au BufEnter     ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHold   ".event_bufspec . " :checktime ".bufspec
        exec "au CursorHoldI  ".event_bufspec . " :checktime ".bufspec
      " The following events might slow things down so we provide a way to disable them...
      " vim docs warn:
      "   Careful: Don't do anything that the user does
      "   not expect or that is slow.
      if more_events
        exec "au CursorMoved  ".event_bufspec . " :checktime ".bufspec
        exec "au CursorMovedI ".event_bufspec . " :checktime ".bufspec
      end
    augroup END
    let msg = msg . 'Now watching ' . bufspec . ' for external updates...'
  end
  " If they want to disable it, or it is defined and they want to toggle it,
  if l:disable || (l:toggle && l:defined)
    if l:autoread
      let msg = msg . 'Autoread disabled - '
      if a:bufname == '*'
        set noautoread
      else
        setlocal noautoread
      end
    end
    " Using an autogroup allows us to remove it easily with the following
    " command. If we do not use an autogroup, we cannot remove this
    " single :checktime command
    " augroup! checkforupdates
    silent! exec 'au! '.id
    silent! exec 'augroup! '.id
    let msg = msg . 'No longer watching ' . bufspec . ' for external updates.'
  elseif l:defined
    let msg = msg . 'Already watching ' . bufspec . ' for external updates'
  end
  echo msg
  let @"=reg_saved
endfunction

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

Solution 6 - Vim

Tail Bundle should do what you want. Note, haven't used it myself.

Solution 7 - Vim

There is a plugin also:

https://github.com/djoshea/vim-autoread

This was the only way I could make this work on OSX.

Solution 8 - Vim

If unix + neovim

:term tail -f <filename>

Obviously this won't work for everyone, but it's how I do it.

Solution 9 - Vim

VIM will warn you when a file has been updated so that you don't overwrite changes that have been made since you opened it. It will prompt you at that point to reload the file.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPatrickView Question on Stackoverflow
Solution 1 - VimPeterView Answer on Stackoverflow
Solution 2 - VimdimbaView Answer on Stackoverflow
Solution 3 - VimPhan Hai QuangView Answer on Stackoverflow
Solution 4 - VimMacMartinView Answer on Stackoverflow
Solution 5 - VimmoeabdolView Answer on Stackoverflow
Solution 6 - VimAlok SinghalView Answer on Stackoverflow
Solution 7 - VimJsalinasView Answer on Stackoverflow
Solution 8 - VimJebView Answer on Stackoverflow
Solution 9 - VimprestomationView Answer on Stackoverflow