Vim和Ctags,相同签名的多个定义未找到。

3

我有一个简单的c++文件,就像这样:

class SomeClass
{
    void SomeMethod() {};
};

class AnotherClass
{
    void SomeMethod() {};
};

如果我使用ctags -R *生成ctags文件,我会得到以下结果:
AnotherClass    main.cpp    /^    class AnotherClass$/;"    c   file:
SomeClass   main.cpp    /^    class SomeClass$/;"   c   file:
SomeMethod  main.cpp    /^        void SomeMethod() {};$/;" f   class:AnotherClass  typeref:typename:void   file:
SomeMethod  main.cpp    /^        void SomeMethod() {};$/;" f   class:SomeClass typeref:typename:void   file:

正如您所看到的,SomeMethod 的定义条目与 vim 中的 tftn 中的相同,始终显示文件中的第一个定义。

我还可以使用 ctags --fields=+n * 添加行号,结果如下:

...
AnotherClass    main.cpp    /^    class AnotherClass$/;"    c   line:6  file:
SomeClass   main.cpp    /^    class SomeClass$/;"   c   line:1  file:
SomeMethod  main.cpp    /^        void SomeMethod() {};$/;" f   line:3  class:SomeClass typeref:typename:void   file:
SomeMethod  main.cpp    /^        void SomeMethod() {};$/;" f   line:8  class:AnotherClass  typeref:typename:void   file:

但是,如果我使用 ta SomeMethodtn,vim 也会始终跳转到第一个 SomeMethod 的定义。

我在这个版本中使用了 ctags:

Universal Ctags 0.0.0(2614dbe1),版权所有 (C) 2015 Universal Ctags Team Universal Ctags 源自 Exuberant Ctags。 Exuberant Ctags 5.8,版权所有 (C) 1996-2009 Darren Hiebert 编译时间:Sep 5 2019, 13:10:38 URL: https://ctags.io/ 可选的编译特性: +wildcards, +regex, +iconv, +option-directory, +xpath, +yaml, +packcc

而 vim 是:

VIM - Vi IMproved 8.1 Patch 1-1713

3个回答

2
我自己找到了一个简单的解决方案:
ctags --excmd=number *

完成了工作。

在标签文件的第三列中,我们可以找到excmd,它是vim用来查找文件中位置的命令。

SomeMethod  main.cpp    /^        void SomeMethod() {};$/;" f   line:8  class:AnotherClass  typeref:typename:void   file:

变成

SomeMethod  main.cpp    8;" f   line:8  class:AnotherClass  typeref:typename    :void   file:

现在vim不会搜索在标签文件中重复的表达式,而是直接跳转到excmd所在的行。


1
如果您向文件中添加行,行号将会发生变化,这是一个问题。 - geza
1
@geza 很清楚!拥有过时的标签文件可能导致错误的查找结果。更改函数签名将导致默认情况下无法找到的行。一个完美的解决方案将是类似于“查找正则表达式的第n行”。但是,这只在文件中没有其他地方(比如注释中)出现相同的正则表达式时才有效。简单的解决方案:重新生成标签文件即可纠正错误的查找。即使对于大型项目,也只需要几秒钟。没有问题! - Klaus

2
尝试使用--excmd=combine。它会在模式前面添加行号。
$ cat /tmp/main.cpp 
class SomeClass
{
    void SomeMethod() {};
};

class AnotherClass
{
    void SomeMethod() {};
};
$ ./ctags -o - --excmd=combine /tmp/main.cpp
AnotherClass    /tmp/main.cpp   5;/^class AnotherClass$/;"  c   file:
SomeClass   /tmp/main.cpp   0;/^class SomeClass$/;" c   file:
SomeMethod  /tmp/main.cpp   2;/^    void SomeMethod() {};$/;"   f   class:SomeClass typeref:typename:void   file:
SomeMethod  /tmp/main.cpp   7;/^    void SomeMethod() {};$/;"   f   class:AnotherClass  typeref:typename:void   file:
$ ./ctags -o - --excmd=combine -B /tmp/main.cpp
AnotherClass    /tmp/main.cpp   7;?^class AnotherClass$?;"  c   file:
SomeClass   /tmp/main.cpp   2;?^class SomeClass$?;" c   file:
SomeMethod  /tmp/main.cpp   4;?^    void SomeMethod() {};$?;"   f   class:SomeClass typeref:typename:void   file:
SomeMethod  /tmp/main.cpp   9;?^    void SomeMethod() {};$?;"   f   class:AnotherClass  typeref:typename:void   file:

1

你需要以下其中一种方式:

  • 传递正确的参数给:tag和其他相关函数
  • 或者使用:tselect
  • 或者使用一个能够帮助区分/选择感兴趣重载的插件(比如我以前的lh-tags插件)
  • 或者使用更现代化的解决方案,例如LSP服务器:最近我发现coc+ccls非常好用,因为它可以根据上下文自动识别光标下的确切重载,这是基于标签的解决方案无法实现的。

你没有理解重点:我遍历标签列表并始终获取文件中的相同行。我知道如何使用tftn进行导航,就像我在问题中已经写过的那样。但是所有这些都以源代码的相同行结束。正如您可以在标签文件中看到的那样,两行是相同的!添加行号被vim忽略了! - Klaus
@ Klaus 语言服务器应该可以解决这个问题,我建议你看看它作为使用ctags的替代方案。 - filbranden
1
@Klaus。我的错,我误读了你的问题。看起来像是一个bug,请在GitHub上的vim存储库中提交一个bug报告/问题。 - Luc Hermitte
似乎不是一个错误。我的理解是:tags文件在第三列中呈现了一个excmd。如果行完全相同,vim就无法找到正确的行。但是ctags除了另一个excmd之外,还有一个简单的“转到行”的选项。请参考我的回答。 - Klaus

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