vim可以监视文件的实时更改


104

我的问题类似于此如何实时监视文本文件, 但我想在vim中执行此操作。我知道我可以读取打开的文件使用tail -f sample.xml文件,并且在将新内容写入文件时,它还会将新内容写入屏幕。文件更新后,vim可以自动填充新数据吗?

Answers:


101

您可以:set autoread使vim在文件更改时读取文件。但是,(取决于您的平台),您必须给予重点关注。

从帮助中:

当检测到文件在Vim外部已被更改并且在Vim内部尚未被更改时,请自动重新读取。删除文件后,不会完成此操作。


5
感谢您的提示!这看起来很有希望,但是在我的系统上不起作用:(我正在使用Mac10.6.2 iTerm和vim版本7.2.303,该版本使用MacVim编译。我可以尝试任何其他评论吗?
Patrick

嗯,那很奇怪。您使用的是macvim gui还是终端版本?它与我预先下载的macvim gui一起工作。(如上所述,我确实必须单击该应用程序以使其具有焦点。)
Peter

1
我正在终端中进行测试,使用gvim(MacVim GUI)之后,该功能开始起作用!正如您提到的,我需要集中精力gvim来更新内容。您有没有技巧来更新它,即使没有集中精力?再次感谢您的帮助。
帕特里克

3
不幸的是,我不知道解决方案。如果vim可以在不改变焦点的情况下做到这一点,我会感到很惊讶-这将要求vim轮询文件系统以查看其更改时间。我认为您需要一个插件。
彼得

2
@Peter我前一段时间做了一个这样的插件。另请参阅此问题及其答案。有关autoread工作原理及其局限性的更多详细信息。
马丁·图尔诺伊

63

不知道自动,但您可以输入:

:e!

重新加载文件


尽管此方法不会自动更新内容,但会显示更新后的内容。感谢您的回答!
帕特里克

31

将以下内容放入您的.vimrc

“在正常模式下闲置4s后检查一次
设置自动读取                                                                                                                                                                                    
au CursorHold *检查时间                                                                                                                                                                       

大!即使自上次重新加载以来更改了该文件,即使显示警告也可以正常工作。
zoujyjs 2014年

1
第一个答案对我不起作用,但这行得通!:-)
尼卡比曹

4
“每4秒”是不正确的。在正常模式下闲置4秒钟后,这只会检查一次。因此,如果您长时间不在另一个缓冲区中执行任何操作,则不会对其进行更新,但是如果您只是移动光标并等待4s便会进行更新。另一种选择是手动调用“:checktime”进行更新(设置自动读取后)。不幸的是,vim中似乎没有任何形式的轮询支持,因此对OP的问题没有真正的答案。
David Ljung麦迪逊·斯特拉2015年

1
刚遇到这个。如果您更改检查时间以调用自定义函数,并在函数末尾添加“ call feedkeys(“ lh”)“,则它将每4秒触发一次。
flukus 2016年

@DavidLjungMadison,您是对的,我将编辑该帖子以避免该错误
Phan Hai Quang

9

就像@flukus在对上一个答案的注释中所说的那样call feedkeys["lh"](您可以将光标向右移动,然后向左移动,通常在查看日志文件时不会造成伤害)

因此,如果您将其余的答案结合在一起,则可以使用oneliner,可以在需要时从ex(whitin vim)运行:

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


(如果您想(几乎)跳到文件末尾,只需在Feed键中使用“ G”而不是“ lh”)

说明:
- 自动读:读取来自外部的变化时,该文件(但它自身不工作,不存在内部定时器或类似的东西,它只会读取时VIM中前做一个动作,像这样的命令文件。:!
- CursorHold * checktime:当用户未在'updatetime'中指定的时间(默认为4000毫秒)中移动光标时,将执行checktime,它检查文件外部的更改
- 调用feedkeys(“ lh”):光标向右和向左移动一次,然后什么也没有发生(...这意味着CursorHold被触发,这意味着我们有一个循环

此外,您可以:set syntax=logtalk为日志着色

要在使用时停止滚动call feedkeys("G"),执行:set noautoread-现在vim会告诉该文件已更改,并询问是否要读取更改)

(这有副作用吗?)

编辑:我看到一个副作用:如果一个人使用Feed键使用“ G”,它将向下滚动每个当前打开的缓冲区?因此,无法在splittet窗口的左缓冲区中工作,而让右缓冲区自动向下滚动日志文件


4

将此粘贴到您的.vimrc中,它应该像老板一样工作。(摘自: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)

1
这是解决终端自动读取缺点的首选答案。
mcanfield

3
@mcanfield不,不是,因为它仍然不会“监视更改”。您仍然需要激活Vim,并且它仍会在有限的事件集上进行轮询(不监视)。CursorHold运行一次。因此,如果您去喝咖啡或在另一个窗口中做某事,它将不会更新。
马丁·图尔诺伊

4
该脚本还捆绑为Vim插件:vim-autoread
stephen.hanson's

1
@ stephen.hanson感谢您的链接,该插件对我来说运作良好!
Tropilio


2

如果Unix + Neovim

:term tail -f <filename>

显然,这并不适合所有人,但我就是这样做的。



0

文件更新后,VIM会警告您,以免覆盖自打开文件以来所做的更改。它将提示您重新加载文件。


1
感谢您的回答,但是当我的系统中的文件被更改时,vim并没有警告我:(
Patrick
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.