Vim:在vimrc中有条件地使用fugitive#statusline函数

7

我在很多机器上使用相同的vimrc,其中有些安装了fugitive.vim插件,而有些没有。我喜欢在我的状态栏中包含fugitive#statusline(),但是在没有安装插件的机器上,这会导致错误。

有没有一种方法可以在调用set statusline之前检查此函数的存在?我尝试过使用exists,但由于某种原因(加载顺序?)它不起作用。

if exists("*fugitive#statusline")
  set statusline=%<\ %f\ %{fugitive#statusline()} ... (other stuff)
endif

我也尝试使用silent!命令前缀来消除错误,但似乎也不起作用。
5个回答

10

这是一个快捷方式:

set statusline+=%{exists('g:loaded_fugitive')?fugitive#statusline():''}

这个不起作用。我尝试过了,但是在执行vimrc时,变量g:loaded_fugitive要么为空,要么不存在。 - Christopher
@Christopher:请检查您的vim-fugitive安装,因为g:loaded_fugitive是在fugitive.vim中定义的,并且这种插值是在评估状态行时完成的,而不仅仅是执行vimrc时。 - tungd
@tungd,除非您手动触发加载某些内容,否则没有理由在vimrc之前加载'g:loaded_fugitive'。 - ZyX
2
@ZyX:实际上,插件总是在 vimrc 之后加载,这在 :help initialization 中清楚地记录下来。然而,由于 %{} 表示每当状态行更新时评估表达式,因此仍然可以按预期工作。 - tungd
@tungd,你说得对。虽然我通常会避免这种解决方案(我是指,在必要的情况下进行 100500 次检查而只需要 1 次),但它是有效的,并且不会增加太多额外负担。 - ZyX

8
由于fugitive在autoload目录中未定义fugitive#statusline,因此无法使用“silent!call”/“exists”技术进行嗅探(感谢@Christopher)。然而,有一些替代方法:
- 在您的“statusline”选项中放置一个三元分支,如@tungd所建议的。 - 在像@Christopher建议的“after/plugin”文件中设置“statusline”。这解决了问题,但意味着您的状态行定义在一个相当不可能的地方,因此最好在您的“~/.vimrc”文件中加上一个漂亮的注释。 - 只需在您的“~/.vimrc”文件中定义该函数即可。
例如:
if !exists('*fugitive#statusline')
  function! fugitive#statusline()
      return ''
  endfunction
endif
  • 另一种选择是使用Fugitive定义的autocmd事件。请注意,这只会在Fugitive检测到git目录时触发。

将类似下面的内容放入您的~/.vimrc文件中:

augroup fugitive_status
  autocmd!
  autocmd user Fugitive set statusline=%<\ %f\ %{fugitive#statusline()} ...
augroup END

我个人认为@tungd的解决方案最简单。然而,定义一个虚拟函数将是我的下一个选择。如果已安装Fugitive,则Fugitive会覆盖它。最好的部分是这可以保持你的'statusline'选项整洁清晰。


虚拟函数应该包含 return ''。否则它会返回数字 0,并将其显示出来。 - ZyX

4

我想我已经想出了如何实现这个问题。需要在插件加载完成后检查fugitive#statusline()是否存在。在此之前,没有任何与fugitive相关的变量或函数被加载。

请将此代码文件添加到$VIMRUNTIME/after/plugin路径中:

" $VIMRUNTIME/after/plugin/fugitive-statusline.vim
if has("statusline") && exists('*fugitive#statusline')
    " git fugitive statusline
    set statusline=%<%f\ %h%m%r%{fugitive#statusline()}%=%-14.(%l,%c%V%)\ %P

    " show statusline always
    set laststatus=2

    " turn off ruler
    set noruler
endif

请解释一下。autoload/目录中的文件只有在某人尝试使用未定义的函数或变量时才会自动加载。当我们强制加载这些函数和变量时,可能触发自动加载的原因就被有效地清除了,从而避免了第二次自动加载文件的情况。无论其中的文件是否已经被加载过,插件目录都不会在vimrc之后被引用,也不会像其他类似的目录一样被引用。 - ZyX
该死的逃犯插件在plugin/fugitive.vim中定义了此函数,而不是应该位于autoload/fugitive.vim中(根据函数名称),这意味着我的解决方案无法正常工作(它仍然没有触发任何运行,更不用说乱序运行了),Peter Rincker的解决方案也是如此。如果函数在autoload/中定义,则适用先前的评论,并且@Peter Rincker的答案就变得好了。加载autoload/fugitive.vim仍然不会引起任何麻烦,但它根本不存在。 - ZyX
将我的两个评论复制到我的答案中(它已被删除),因为我不确定您是否可以看到已删除答案的评论。为了跟进对话:“我们真的应该颠覆处理顺序,但是按照顺序运行autoload/fugitive.vim。这可能会产生意想不到的后果。- Christopher”是第一个评论,我的评论是回复它的。我的答案是使用:runtime加载autoload/fugitive.vim,然后检查函数是否存在。 - ZyX
@ZyX Fugitive 真的让我感到困惑。我已经删除了我的帖子,因为它不起作用。 - Peter Rincker

1
你可以尝试检查逃犯插件的已加载变量?
if exists('g:loaded_fugitive')
   set statusline=%<\ %f\ %{fugitive#statusline()} ... (other stuff)
endif

虽然如果逃犯#状态行不存在,这可能不是很有效!


这个不起作用。我试过了,但变量 g:loaded_fugitive 在执行 vimrc 时要么为空,要么不存在。 - Christopher

0
在你的vimrc或init.vim文件中。
set statusline=%F%r%h%w%=(%{&ff}/%Y)\ (line\ %l\/%L,\ col\ %c)\

if exists("*fugitive#statusline")
  set statusline+=%{fugitive#statusline()}
endif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接