Vim跳到错误的标签

时间:2018-11-07 14:58:48

标签: vim ctags

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

2 个答案:

答案 0 :(得分:3)

如果您查看: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(\%(\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!

答案 1 :(得分:1)

根据Ingo Karkat的回答,这是一个可能适合您的解决方案。如果您使用void append(text *t1, text *t2) { int length1 = strlen(t1->content); int length2 = strlen(t2->content); int lengths = length1 + length2; // calculate the required length. You can change this to have some "reserve" such as in newText. In this example, it will be 24 t1->content = realloc(t1->content, lengths); // set the correct size for the buffer for (int i = length1; i < length1 + length2; i++) { t1->content[i] = t2->content[i - length1]; t1->content[i + 1] = '\0'; } // append the second string t1->capacity = lengths; printf("%s \n", t1->content); printf("%d \n", t1->capacity); } 运行ctags(至少是旺盛的Ctags),它将输出行号而不是标签位置的搜索命令,这将解决歧义。

--excmd=number

不利之处在于,一旦您开始编辑文件,这些标记将无效,直到您再次运行ctags为止。搜索模式比行号更不容易受到这种影响。

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