Vim 维姆跳到了错误的标签上

Vim 维姆跳到了错误的标签上,vim,ctags,Vim,Ctags,标题说明了问题所在,下面是上下文。我有一个微小的C++文件 void f( int x ) { } void f( ) { } 我在上面运行CTAG ctags --recurse --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f tags f.C 检查标记文件时,会按预期显示f的两个条目,并带有正确的签名 当我尝试在Vim中使用它时,Vim使用ctrl-

标题说明了问题所在,下面是上下文。我有一个微小的C++文件

void f(
        int x
      ) { }

void f(
      ) { }
我在上面运行CTAG

ctags --recurse --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f tags f.C
检查标记文件时,会按预期显示f的两个条目,并带有正确的签名

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

如果您查看,Vim使用第三列(名为
{tagaddress}
)作为(搜索)命令()。在生成的标记文件中,它如下所示:

f   foo.cpp /^void f($/;"   f   signature:( )
f   foo.cpp /^void f($/;"   f   signature:( int x )
<> >强>两个重载的搜索模式(/^ Valf($/< /Cord>)是相同的>;这就是为什么每个标签跳跃都会定位第一个实例的原因。换句话说,尽管标签程序添加了签名,但不幸的是,VIM没有考虑它。 因此,解决此问题的明显方法是重新格式化源代码,使签名(部分)包含在同一行中

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

解决这一问题的一个更正确(但也是更复杂的)途径是扩展<代码> CTAGS < /Case>程序来识别这些歧义,然后用正的前瞻来扩充模式,也考虑下面行中的内容。

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

不幸的是,Vim似乎不理解这种语法(无论有无前瞻);我只是得到了
E435:找不到标记,只是猜测!

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

ctags --recurse --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f tags --excmd=number f.C
这样做的缺点是,一旦开始编辑文件,标签将无效,直到您再次运行CTAG。搜索模式比行号更容易受到影响


还有其他一些答案(只有一个)这涵盖了根据更改自动运行CTAG;这两种方法的某些组合可能适合您。

使用更传统的编码风格的原因。回答不错!是的,感谢确认,这就是我担心的!对于如此短的函数,编码风格看起来有点奇怪,但我的实际用例有五个参数,其中两个是模板参数实例化,将它们以列格式分别写在单独的行上是完全合理的。它仍然会造成签名的模糊性。你刚刚击败了我!这对我来说是一个非常有效的解决方案。此外,如果我创建两个标记文件,在行号和regexp的基础上,我可以在它们之间切换,只需按一下键,就可以获得最好的both worlds.By kine number对于我的大多数(相当大的)代码库来说都是好的,当我有了方向时就切换到regexp。