Vim语法和文件类型检测的行为非常奇怪

9

我有一个文件,名为WrongFileTypeDetection.R,其中包含以下文本:

# This file is sometimes wrongly detected as a conf file

我也有两个版本的_vimrc,我原以为它们完全相同。然而,当我使用第一个版本时,上述文件被错误地检测为“conf”文件,尽管我已经明确要求所有以.R结尾的文件都设置为filetype=r。当我改用第二个版本(将“syntax on”移动到augroup定义后面)时,检测再次正常工作。请注意,这是我唯一的配置(在调试期间,我移开了我的标准vimrc)。

第一个版本:

syntax on
augroup filetypedetect
    autocmd! BufRead,BufNewFile *.r,*.R     setfiletype r
augroup END

第二版:

augroup filetypedetect
    autocmd! BufRead,BufNewFile *.r,*.R     setfiletype r
augroup END
syntax on

看起来vimrc对这两个文件的特定顺序非常敏感。考虑到其中一行是一个autocommand,无论如何都会在较晚的时间运行,那么为什么会出现这种情况呢?这是Vim中的一个bug还是我没有理解的一个功能呢?

3个回答

11

针对你的问题,简单的答案是这些行不应该出现在你的vimrc文件中。官方支持的处理方式是在你的.vim目录下创建一个filetype.vim文件,其中包含以下内容:

" my filetype file
if exists("did_load_filetypes")
  finish
endif

augroup filetypedetect
  au! BufRead,BufNewFile *.r setfiletype r
augroup END

关于您的代码为什么会表现出现在这样的行为,实际上比@too much php's answer暗示的要复杂得多。
在您的vimrc的第一个版本中,文件类型检测是通过您的"syntax on"行初始化的。这是通过设置一个autocmd来实现的,当打开一个扩展名为.r的文件时,这个autocmd会调用filetype.vim中的函数s:FTr()。
然而,您的autocmd!行覆盖了这个现有的autocmd1,因此s:FTr()函数从未运行2。然后,您的autocmd被触发,但它并没有设置文件类型,因为setfiletype命令认为文件类型已经被设置3。
接着,因为文件类型仍然没有被真正地设置,Vim试图根据文件的内容分配一个文件类型,并最终将其分配给conf类型4。
所有这些的最佳参考资料是:help filetype。特别是在您的情况下,:help new-filetype和:help remove-filetype。:verbose命令也非常方便,可以帮助您确定哪些设置是由哪个脚本设置的。

1:由于有!。如果您删除此!,则会发现文件类型被正确设置。然而,这不是正确的解决方案,因为这样您将允许文件被设置为一种类型(并应用该文件类型的所有设置),然后再更改为另一种类型。如果第二个文件类型没有覆盖所有这些设置,则可能会保留一些设置,这可能不是您想要的。

2:在使用两个不同的vimrc文件时,请尝试运行:set autocmd BufRead *.r。注意给出的输出差异。

3:请参阅:help setfiletype。请注意,如果您在vimrc的第一个版本中将行setfiletype r更改为set ft=r,则文件类型将被设置为r。但是,请参见脚注1,了解为什么这不是最佳解决方案。

4:...在一行被注释的代码中:“最后检查一下,这只是猜测”


谢谢你,Rich。这是一个非常详细和周到的答案。我会记住它,并在需要在Vim中调整文件类型检测时参考它。 - Magnus
@Magnus 不用谢。我没有将它添加到答案中,因为我认为里面已经有足够的信息了,但我也使用 vim -D 进行了一些调试,以帮助确定在什么时间设置了什么。 - Rich
不幸的是,这个问题似乎至少在CentOS 7.6.1810中出现了,vim版本为7.4.160-5,我实际上使用~/.vim/filetype.vim,并且只有选项用于类型,例如在.vimrc中的格式选项。这就是我遇到这个问题的原因。这非常令人恼火,因为源文件/头文件中的任何C预处理器指令都会使vim在下次打开时将其检测为conf文件。从而完全改变颜色选项等。 - Pryftan
@Pryftan 虽然症状相同,但听起来根本原因对你来说略有不同。为了调试,您可以首先仔细检查您的自动命令是否被触发,然后在文件类型错误的缓冲区中运行命令 :verbose set filetype? 来检查覆盖文件类型的内容。 - Rich
@Rich Ta。实际上,它似乎已经解决了。老实说,我不知道是什么原因。我太疲惫了,不知道该相信什么。无论如何,现在看起来没问题了。我本来觉得这很奇怪,结果也确实如此。更奇怪的是,我什么都没有改变,也没有任何更新。无论如何,感谢您的建议。实际上,我确实检查了*:set filetype,但没有检查:verbose ...*。我注意到的是,如果文件中有以'#'开头的行(可能只有开头,但对于空格没有任何想法),就会出现这种情况。而且只有在打开文件后才会出现这个问题:如果我在新文件中添加它,那就不是问题。 - Pryftan

7
在你的第一个版本中,syntax on会在你添加自动命令之前触发文件类型检测。

2

你好,欢迎来到 Stack Overflow!提供潜在解决方案的链接总是受欢迎的,但请添加链接周围的上下文,以便您的同行用户了解它是什么以及为什么存在。始终引用重要链接的最相关部分。想象一下页面被移动到另一个服务器或直接链接发生变化的情况 - 未来的用户将无法从答案中受益。请查看 如何回答 - Jesse
这个方法可以运行,但并不是最理想的。请参考我回答中的脚注1以获取更多细节。 - Rich

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