Vim跳错了标签



标题说明了问题,所以这里是上下文。我有一个很小的C++文件

void f(
int x
) { }
void f(
) { }

我在上面运行ctags。

ctags --recurse --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f tags f.C

检查标记文件会显示f的两个条目,它们具有正确的签名。

当我尝试在Vim中使用它时,Vim会用ctrl-]定位函数,但当我使用:tnext和:tprev时,消息会显示tag 1 of 2tag 2 of 2,但光标不会在它们之间移动。

如果查看:help tags-file-format,Vim会使用第三列(名为{tagaddress}(作为(搜索(命令(:help tag-search(。在生成的标签文件中,它看起来像这样:

f   foo.cpp /^void f($/;"   f   signature:( )
f   foo.cpp /^void f($/;"   f   signature:( int x )

两个重载(/^void f($/(的搜索模式相同;这就是为什么每个标签跳转都会定位第一个实例!换句话说,虽然标签程序添加了签名很好,但不幸的是Vim没有考虑

这样,解决这个问题的明显方法是重新格式化源代码,使签名的(部分(包含在同一行中。然后,会有不同的模式:

b   bar.cpp /^void b()$/;"  f   signature:()
b   bar.cpp /^void b(int x)$/;" f   signature:(int x)

解决这一问题的一个更正确(但也更复杂(的途径是扩展ctags程序来识别这些模糊性,然后用正向前瞻来增强模式,以考虑下一行中的内容。

f   foo.cpp /^void f(%(ns*int x)@=/;"  f   signature:( )
f   foo.cpp /^void f(ns*)/;"  f   signature:( int x )

不幸的是,Vim似乎不理解这种语法(无论有没有前瞻性(;我刚拿到E435: Couldn't find tag, just guessing!

根据Ingo Karkat的回答,这里有一个可能适用于您的解决方案。如果使用--excmd=number运行ctags(至少是Exuberant Ctags(,它将输出行号,而不是搜索标签位置的命令,从而解决歧义。

ctags --recurse --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f tags --excmd=number f.C

这样做的缺点是,一旦开始编辑文件,在再次运行ctags之前,标记将无效。搜索模式比行号更不容易受到这种影响

还有一些其他的答案(Vim自动生成ctag就是其中之一(涵盖了在更改时自动运行ctag;这两种方法的结合可能对你有用。

最新更新