我正在使用VIm做各种事情(在本例中为gVim),包括监视写入文件的输出;我使用autoread来使Vim重读该文件,只要我将键盘焦点切换到该文件,它就会执行该操作。

即使我不切换键盘焦点,也可以使Vim更新缓冲区吗? ?我已经尝试设置checktime,但是当键盘焦点位于其他位置时,它似乎没有任何作用。

我正在监视的输出将完全替换输出文件。而且我不希望Q4312079q它。还有其他选择,例如每次都管道传输到新实例,或管道传输到tail -f之类,但是如果可以使用VIm完成,那将是很酷的。

评论

@Carpetsmoker CursorHold事件如何?如果Vim没有焦点,它应该每n秒触发一次。

@muru不,CursorHold仅执行一次,其明确记录为:“如果您离开Vim来煮咖啡,则不会每隔'updatetime'ms触发一次。:)“

我再次删除了gvim标记,希望没问题;-)正如我所看到的,这个问题与gVim无关,因为焦点更改只是Vim检查文件是否已更改的一个事件(有一整堆,请参阅我的答案以了解详细信息)。大多数(如果不是全部)的改进方法在Vim和gVim中都可以正常工作。

@Carpetsmoker啊,我的印象是gVim在有键盘焦点的情况下会定期检查(因此使它成为gVim问题),但看来我弄错了。感谢您清理。

#1 楼

:help 'autoread'没有很多有关它如何工作的信息,但是Vim会检查打开的文件在某些​​事件中是否被修改(它总是这样做),如果能够启用autoread,它将自动重新加载它。

具体来说,它检查何时:



使用:checktime
输入缓冲区;

使用:diffupdate;

:e是针对已经具有缓冲区的文件发出的;
使用!执行外部命令;
返回到前台(^Zfg,仅当Shell具有作业控制权时) ;

对于gVim,也可以在以下情况下完成:


关闭“右键单击”菜单(通过选择某些内容或仅通过关闭它) ;
焦点已更改(这是您已经注意到的);
如果从菜单中使用“文件->打开”,“文件->另存为”,则关闭弹出的文件浏览器对话框。以及其他一些地方)。

我通过查找所有对Vim的调用从Vim源中收集了这些信息。 buf_check_timestamp()check_timestamps()功能和need_check_timestamps设置为TRUE的位置。该列表可能由于我查看了2015年而过时,但乍一看似乎仍然(大多数)准确。

关键是Vim仅检查文件是否在文件中被修改。情况非常有限。这是有道理的,因为每n秒轮询潜在的大量缓冲区可能会非常昂贵。

自Vim 7.4.1578(2016年3月)以来,就有一些计时器,您可以使用它们在每n次运行checktime秒(此答案的先前版本是2015年的版本,使用了变通方法)。例如,仅对某些缓冲区执行此操作,您可以使用以下命令:

set autoread
fun! s:checktime(timer_id)
    checktime
endfun
autocmd BufNewFile,BufReadPost xxx
            \ call timer_start(3000, function('s:checktime'), {'repeat': -1})


的缺点是设置了很多计时器,所以也许更好的方法是设置一个在所有缓冲区上循环的计时器,然后再次设置计时器(这样就不必冒着同时运行两个计时器的风险) :

set autoread
fun! s:checktime(timer_id)
    for buf in filter(map(getbufinfo(), {_, v -> v.bufnr}), {_, v -> buflisted(v)})
        echom buf
        exe 'checktime' buf
    endfor
    call timer_start(3000, function('s:checktime'))
endfun
call timer_start(3000, function('s:checktime'))


我确实注意到Vim眨了眨眼,即使没有任何变化。不知道是否有解决该问题的方法(没有看);因此,您可能希望将其添加为仅在需要时运行的命令:

set autoread
let s:autoread_timer = -1
fun! s:checktime(timer_id)
    checktime
endfun

command! -bang Autoread 
            \  if <bang>0
            \|   call timer_stop(s:autoread_timer)
            \| else
            \|   let s:autoread_timer = timer_start(1000,
            \        function('s:checktime'), {'repeat': -1})
            \| endif


有很多方法可以对此进行进一步改进,例如仅针对当前缓冲区,对运行频率的更多控制等等),但是这个想法应该很清楚:-)

#2 楼

从这个答案(参考PhanHaiQuang的答案和flukus的评论)

一个人可以在需要时从ex(whitin vim)运行此oneliner(或将每个命令放在vimrc中,以获取日志文件)打开。)

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

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

#3 楼

我做了一个小插件vim-autoread,它使用tail -f异步更新后台的缓冲区。显然,这需要Vim版本8的工作功能。

使用:AutoRead将其打开,并使用:AutoRead!将其关闭。

评论


兼容NeoVim的版本会很棒!

–安德鲁(Andrew)
17年8月1日在22:05

@AndrewMacFie我不明白,为什么这在Neovim上不起作用。

–克里斯蒂安·布拉班特(Christian Brabandt)
17年8月2日在6:10

我认为NeoVim中缺少Vim 8工作支持吗?

–安德鲁(Andrew)
17年8月2日在17:52

@AndrewMacFie哦,那可能是真的。由于我不使用neovim,因此无法使其兼容NeoVim。但是,公关将是受欢迎的:)

–克里斯蒂安·布拉班特(Christian Brabandt)
17年8月2日在19:05

很公平 : )

–安德鲁(Andrew)
17年8月2日在22:18

#4 楼

在Neovim中,您可以使用以下命令来打开运行tail命令的终端缓冲区。

:enew | call termopen('tail --follow=name --retry /path/to/file.log')


即使删除并重新创建了文件,该命令也将继续起作用。

或将以下内容添加到您的$MYVIMRC

" :Tail /path/to/file
function! Tail(file)
  enew
  call termopen('tail --follow=name --retry ' . fnameescape(a:file))
endfunction
command! -nargs=1 Tail call Tail(<f-args>)