我的.vimrc
中有以下几行:
:function GitCommitMsg()
: set tw=62
: if getline(1) == ""
: 1
: r!git diff -w --minimal --cached
: 1d
: endif
: set syntax=diff
:endf
:au BufRead,BufNewFile COMMIT_EDITMSG call GitCommitMsg()
多年来,上述内容在 Vim 7.x 上运行良好,但在 Ubuntu 18 上的 Vim 8 下开始行为不端。
if
语句的内部是为新提交执行的。这个想法是在进行新提交时提供一些内容,但否则就不理会消息。
当该内部执行时,set tw=62
和set syntax=diff
都不会生效。观测值分别为72
和gitcommit
。
不知何故,条件:r!
调用导致了问题。如果我们将其注释掉:
:function GitCommitMsg()
: set tw=62
: if getline(1) == ""
: 1
": r!git diff -w --minimal --cached
: 1d
: endif
: set syntax=diff
:endf
:au BufRead,BufNewFile COMMIT_EDITMSG call GitCommitMsg()
然后set tw=62
和set syntax=diff
在所有情况下生效。
请注意,:r!git diff
确实有效:git diff ...
的输出加载到缓冲区中,前导空行由1d
删除。
原因不是具体git diff
或其产生的内容;无论我们使用:r!
读取什么命令的输出,问题仍然存在。 因此,例如,这仍然存在问题:
:function GitCommitMsg()
: set tw=62
: if getline(1) == ""
: 1
: r!echo foo
: 1d
: endif
: set syntax=diff
:endf
:au BufRead,BufNewFile COMMIT_EDITMSG call GitCommitMsg()
我们如何在au
处理过程中将命令的输出读入缓冲区,而不会产生不必要的副作用,例如设置被破坏?
只需将BufRead,BufNewFile
更改为BufWinEnter
即可解决您的问题。
问题可能是由于在BufRead
时只有缓冲区存在,但尚未选择(甚至尚未创建(的窗口。为了解决这个问题,Vim 利用了一些怪癖,所以你的脚本可能在某个临时窗口的上下文中运行(尝试跟踪win_getid()
值(,之后 Vim 将从"上次使用的窗口"中复制窗口本地选项(例如tw
(等等。
另一点是任意 Ex 命令必须具有窗口上下文才能运行(例如,有win_execute()
,但没有buf_execute()
(。因此,执行:read
也可能导致操纵"临时"。
好吧,这可能是一种猜测而不是解释,但我希望你明白这个想法。