Vim 跳转到错误的标签

问题描述 投票:0回答:3

标题说明了问题,所以这是上下文。我有一个很小的 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
但光标不会在它们之间移动。

vim ctags
3个回答
4
投票

如果你看一下

: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
程序来识别这些歧义,然后使用 positive Lookahead 来增强模式,以考虑下一行中的内容。

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

不幸的是,Vim 似乎不理解这种语法(无论是否有前瞻);我刚刚得到

E435: Couldn't find tag, just guessing!


4
投票

根据 Ingo Karkat 的回答,这里有一个可能适合您的解决方案。如果您使用

ctags
运行
--excmd=number
(至少是 Exuberant Ctags),它将输出行号而不是标签位置的搜索命令,从而解决歧义。

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

这样做的缺点是,一旦您开始编辑文件,标签将无效,直到您再次运行 ctags。搜索模式比行号更不易受此影响。

还有一些其他答案(Vim 自动生成 ctags 是其中之一),涵盖了在更改时自动运行 ctags;这两种方法的某种组合可能对您有用。


0
投票

就我而言,我还有一个过时的 cscope 数据库,并且打开了

cscopetag
,因此 vim 根据 cscope 数据库中的信息跳转到错误的标签。删除或更新 cscope 数据库即可解决该问题。

© www.soinside.com 2019 - 2024. All rights reserved.