可以监视文件的实时更改

我的问题类似于如何实时监控文本文件 但我想用 Vim。我知道我可以使用 tail -f sample.xml文件读取打开的文件,当新内容写入文件时,它也会将新内容写入我的屏幕。当文件更新时,我能让 vim 自动填充新数据吗?

50939 次浏览

不知道什么是自动,但你可以输入:

:e!

重新加载文件

VIM 会在文件更新时发出警告,这样您就不会覆盖自打开文件以来所做的更改。它将在那时提示您重新加载文件。

您可以使用 :set autoread,以便 vim 在文件更改时读取文件。然而(取决于你的平台) ,你必须给它重点。

从帮助:

当检测到文件具有 been changed outside of Vim and it 并没有在 Vim 体内被改变, 自动再读一遍。当 文件已被删除,这是不是 搞定。

在你的 .vimrc中加入以下内容:

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

把这个放在你的.vimrc 中,它应该像老板一样工作

" 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)

如果 unix + nevim

:term tail -f <filename>

显然这不是对所有人都管用,但我就是这么做的。

还有一个插件:

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

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

就像@flukus 在对 上一个答案的评论中说的,你可以使用 call feedkeys["lh"](它将光标向右移动,向左移动,这在查看日志文件时通常不会造成伤害)

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

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


* * * (如果您想跳到(几乎)文件的末尾,只需使用“ G”而不是“ lh”(带反馈键)) * * *

说明:

  • 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 : 当用户在“ updatetime”(默认为4000毫秒)中指定的时间内没有移动光标时,将执行 checktime,检查文件外部的更改
  • 调用反馈键(“ lh”) : 光标移动一次,向右移动一次,向左移动一次。然后什么也没有发生(... 这意味着,CursorHold 被触发,这意味着我们有一个 循环)

此外,您可以 :set syntax=logtalk颜色的日志

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

(这有什么副作用吗?)

编辑: 我看到一个副作用: 如果使用“ G”作为反馈键,它将向下滚动每个当前打开的缓冲区? !因此,当让右缓冲区自动向下滚动日志文件时,不可能在 splitet 窗口的左缓冲区中工作

若要在打开特定文件时启用重新加载,可以将其添加到 .vimrc并使用类似于 vim: set ft+=.watch:的建模。它利用这个特性为一个缓冲区设置多个文件类型(见下文) :

vim9script


command WatchFiles {
autocmd! AUWatchFile FocusGained,VimResume,BufEnter,WinEnter,CursorHold * checktime
autocmd! AUWatchFile BufEnter,InsertEnter,CursorHold,CursorHoldI <buffer> checktime
setlocal autoread
checktime
}


command UnwatchFiles {
autocmd! AUWatchFile
set autoread<
}




# To enable this, you may use e.g. a modeline: `vim: set ft+=.watch`
def WatchAutomatically()
# Check if the "list" of filetypes (a dot separated string) contains 'watch'.
if -1 != match(&filetype, "\\(^\\|\\.\\)watch\\($\\|\\.\\)")
WatchFiles
endif
enddef




augroup AUWatchFile | augroup END
autocmd BufWinEnter * call WatchAutomatically()

更多细节

You are able to set multiple filetypes separated by .:

当一个点出现在值中时,这将分隔两个文件类型 例如: /* vim: set filetype = c.doxygen: */~

参见 :help 'filetype'。 请记住,您应该首先操作文件类型,然后在 Modeline 中设置其他选项。否则,这些选项可能会被文件类型的特定设置覆盖。

顺便说一下,上面是一个 Vim9脚本(我今天发现的) ,把它翻译回一个古老的 Vim 脚本很简单:

  • 使用 "进行注释。
  • 像这样转换多行命令:
    command UnwatchFiles
    \ autocmd! AUWatchFile
    \ | set autoread<
    
  • 拆下 vim9script线。

详情请参阅 :help Vim9-script

缺点

  • 重新加载不限于包含 model 的缓冲区。您可以用 :UnwatchFiles再次禁用它。
  • 这仍然是抛弃民意调查。