标题说明了问题,所以这里是上下文。我有一个很小的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 2
或tag 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;这两种方法的结合可能对你有用。