在没有焦点的情况下,如何使Vim自动读取文件?


29

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

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

我正在监视的输出将完全替换输出文件。而且我没有期待tail -f它。还有其他选择,例如每次都管道到一个新实例中,或管道到less某样东西中,但是如果可以使用VIm完成,那将是很酷的。


@Carpetsmoker活动怎么样CursorHold?如果Vim没有焦点,它应该每n秒触发一次。
muru

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

1
我删除了GVIM再次标签,我希望这没关系;-)在我看来,这个问题是不是真的 gVim的,因为焦点的变化仅仅是一个事件上会先检查文件是否被改变(也有一大堆,请参阅我的答案以了解详细信息)。大多数(如果不是全部)的改进方法在Vim和gVim中都可以正常工作。
马丁·图尔诺伊

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

Answers:


20

更新2015-06-25

  • 我已经放弃了“ shell”方法,因为它太不起作用了。它停止了插入模式并离开了僵尸进程。看看这篇文章的修订历史,您是否真的想看到它。
  • 我已经用它制作了一个插件:auto_autoread.vim。目前,它实际上与下面的代码相同,但是我建议您使用该插件,因为它很可能会收到更新。

怎么autoread办?

要回答这个问题,我们必须首先了解该autoread选项的作用,更重要的是,它不起作用

不幸的是:help 'autoread' ,关于此的信息并不多,它只是说“检测到文件已在Vim之外更改”。Vim如何检测文件已更改?在某些操作上,Vim检查文件的修改时间。

什么时候:

  • :checktime 用来;
  • 输入一个缓冲区;
  • :diffupdate 用来;
  • :e 为已经具有缓冲区的文件发出;
  • 执行外部命令!;
  • 返回到前台(^Z,,fg仅当shell具有作业控制权时);

对于gVim,在以下情况下也可以这样做:

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

我通过查找到所有通话聚集从Vim的源信息 buf_check_timestamp()check_timestamps()其中,功能和位置 need_check_timestamps设置为TRUE

我可能错过了一些事件,但是要记住的关键是Vim仅检查是否在非常有限的情况下修改了文件。它肯定不会“轮询”文件以进行n秒钟的更改,这基本上就是您要执行的操作。

因此,仅出于您的目的,set autoread还不够。

使用Python

这计划将Python线程在后台运行,它将:checktimen秒运行 一次。如果autoread启用,这将刷新缓冲区从磁盘,否则它只会发出警告。

这要求Vim具有+python+python3in :version。它应可在所有平台(包括Windows)上运行。

fun! AutoreadPython()
python << EOF
import time, vim
try: import thread
except ImportError: import _thread as thread # Py3

def autoread():
    vim.command('checktime')  # Run the 'checktime' command
    vim.command('redraw')     # Actually update the display

def autoread_loop():
    while True:
        time.sleep(1)
        autoread()

thread.start_new_thread(autoread_loop, ())
EOF
endfun

您可以使用:call AutoreadPython();您当然可以在autocmd中执行此操作;例如:

autocmd *.c call AutoreadPython()

后记

实际上还有更多的方法,例如,您可以使用诸如entr或Python inotifygamin模块之类的工具 来监视文件的更改,:checktime还可以检查所有缓冲区(如果未提供任何参数),可以通过仅检查单个缓冲区或某个文件。
但是,此答案已经相当长了:-)这些方法应该(希望如此!)在大多数情况下都可以正常工作,或者应该易于适应您的情况。

PS。我也尝试使用Ruby,但是不幸的是,Ruby线程(使用Thread)没有像Python那样在后台运行,所以我无法使其工作(也许还有另一种方法?)


2

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

使用:AutoRead来打开它,并:AutoRead!把它关掉。


NeoVim兼容的版本会很棒!
安德鲁

@AndrewMacFie我不明白,为什么这在Neovim上不起作用。
克里斯蒂安·布拉班德

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

@AndrewMacFie哦,那可能是真的。由于我不使用neovim,因此无法使其兼容NeoVim。不过,我们欢迎PR :)
Christian Brabandt

足够公平
安德鲁(Andrew

1

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

1

从这个答案(指的由一个答案PhanHaiQuang和评论flukus

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

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

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

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.