在vim中获取ctags以进行定义,而不是声明

时间:2009-06-28 10:53:23

标签: vim ctags

我遇到的问题是vim / gvim中的ctags很多时候都会转发前向声明而不是函数的实际定义。

有什么方法可以解决这个问题吗?

10 个答案:

答案 0 :(得分:70)

我认为最简单的方法是使用“g ctrl-]”而不是“ctrl-]”。如果只有一场比赛,它会带你到那里。如果有多个匹配项,它会将它们全部列出,让您选择所需的匹配项,如:tselect。两全其美的。 :)

答案 1 :(得分:9)

您应该可以使用tntp跳转到各种匹配的代码。

  • ^]转到第一场比赛。
  • 如果那不是您想要的匹配项,请键入:tn以转到下一个。
  • 如果您输入:tn次数太多,则可以键入:tp以返回上一个。{/ li>

答案 2 :(得分:8)

我相信默认情况下Vim会转到标记文件中的第一个标记。如果您愿意,可以选择另一个:使用:tj(类似于:tselect,但如果只有一个匹配则自动跳转)或Ctrl-]后跟:tn。)

更改默认值的唯一方法是更改​​标记文件的顺序,但我不相信ctags提供了一个命令行选项来执行此操作。

这并不像听起来那么难,因为你基本上需要一个打开标签文件的脚本,按照'kind'标签对其进行排序并再次将其写回。标签中的“种类”是一个单一的字符,描述它是一个函数(f),一个函数原型(p),一个宏,一个枚举的名称等等。如果你使用Linux,它可以,在理论上,简单如下:

#!/bin/sh
ctags -R -f - . | tac > tags

由于tac会反转文件中的行顺序,因此会自动将定义放在第一位。但是,由于需要维护标头并且Vim更喜欢对标签文件进行排序,因此它会变得有点复杂,所以最好通过文件并按正向顺序对第一个条目(标签名称)进行排序,然后以相反的顺序排序。因此,更复杂的事情可能会更好。

我为无耻的插件道歉,但我写了一个(间接)做你需要的Vim插件。它用于为函数名,宏,枚举等添加许多额外的突出显示组。但是,这样做的其中一个是重新排序标记文件,以便函数实现在函数声明之前,从而实现你想要的(我和你有同样的需求)。如果您不想要任何突出显示功能,您可能很容易将其全部删除:它是一个相当简单的python程序和更简单的Vim脚本,可从my site获得。

答案 3 :(得分:2)

晚会,但对于传入的vim标签googlers:

我发现除了ctags之外使用cscope是最好的方法,至少对于C / C ++来说。它对调用树更加智能,如果失败,你可以将其设置为回退到ctags。每次运行ctags -R时都要运行“cscope -b”。你准备好了。如果您使用下面的设置,您将能够像使用Ctrl - ] / Ctrl-T一样,但您也可以添加漂亮的新跳转,例如跳转到函数声明并显示函数调用者的跳转列表。

" setup
if has("cscope")
    set csto=0                                                                             
    set cst
    set nocsverb
    " add any database in current directory
    if filereadable("cscope.out")
    cs add cscope.out
    " else add database pointed to by environment
    elseif $CSCOPE_DB != ""
    cs add $CSCOPE_DB
    endif
    set csverb
endif

" jump to a function declaration
nmap <silent> <C-\> :cs find s <C-R>=expand("<cword>")<CR><CR>1<CR><CR>
" show a list of where function is called
nmap <silent> <C-_> :cs find c <C-R>=expand("<cword>")<CR><CR>

答案 4 :(得分:1)

:tselect my_little_function 

你会得到一份比赛清单。 或者如果你跳转到标签并且你对它不满意,那么输入

:tselect

您将获得最后一个活动标记的替代列表。

答案 5 :(得分:1)

此选项对我有用

将以下行添加到.vimrc中,现在您可以双击鼠标(在文件中的variable/entry上)跳转到标记的位置。如果找到单个匹配,它将立即跳转。如果多个条目匹配,则会提示用户输入..

:map <2-LeftMouse> g< c-]>

答案 6 :(得分:1)

将以下内容添加到.vimrc文件中:

noremap <c-]> 2<c-]>

这一行导致vim自动跳转到第二个匹配(而不是第一个匹配),这通常是函数定义。

答案 7 :(得分:0)

如果只有一个标记匹配,有几种方法可以让Vim直接跳转到标记,否则会显示标记匹配列表。

您可以使用&#39; tjump&#39;前命令。例如,命令&#39; :tjump func1&#39;将跳转到定义func1,如果它只定义一次。如果多次定义func1,将显示匹配标记列表。

您可以将光标放在标签上,然后按g Ctrl-]

您可以直观地选择文字,然后按g Ctrl-]跳转或列出匹配的标签。

您可以使用&#39; stjump&#39;前命令。这将在新窗口中打开标记列表中的匹配或选定标记。

您可以按Ctrl-W g Ctrl-]执行:stjump。

Help: :tjump, g_Ctrl-], v_g_CTRL-], :stjump, Ctrl-W_g_Ctrl-]

答案 8 :(得分:0)

你可以按 2 然后 CTRL + ] ,这将直接转到第二个匹配,在java中,这通常是实现一些界面。

答案 9 :(得分:0)

之所以会发生这种情况,是因为存储在标记文件中的模式匹配在定义之前找到了声明。

当Exuberant Ctags为标识符创建条目时,它将整个包含行添加为匹配项。

但是,有时前向声明与此模式匹配。在某些编码样式下可能会发生这种情况。

首先,这是一个示例文件foo.c,它没有此问题:

static int foo(int x);
static int foo(int x)
{
}

Ctags创建一个如下所示的条目:

foo foo.c   /^static int foo(int x)$/;" f   file:   signature:(int x)

匹配项以^$为基础,并且由于前向声明以;结尾,因此不匹配。

但是,以下编码约定触发了该问题:

static int foo(
 int x
);

static int foo(
  int x
)
{
}

tags条目现在是:

foo foo.c   /^static int foo($/;"   f   file:   signature:( int x )

这将找到声明的第一行,与定义的第一行没有区别。

解决方法是使这两者有所不同,同时保持在编码约定之内。在这种情况下,我们在C语言中,因此我们可以做的一件事是从定义中删除static

没有存储类说明符的C文件范围声明使用链接声明一个名称。链接类型(内部或外部)是从任何先前指定链接的名称声明中继承的。因此:

static int foo(
 int x
);

int foo(
  int x
)
{
}

现在标签看起来像:

foo foo.c   /^int foo($/;"  f   signature:( int x )

仅匹配定义; Vim不再跳转到第一个声明。

如果该解决方案不可行,则可能有必要编写tags过滤工具,该工具可以扫描tags文件并识别此问题,并修复有问题的标签。例如,对于第二行带有歧义的文件,我们可以像这样手动修复标签:

foo     foo.c   /^static int foo($/;/^static int foo($/;"       f       file:   signature:( int x )

我在标签地址中添加了第二个Ex命令,以再次搜索相同的模式。现在它跳到正确的行。 (注意:但是,如果前向声明是文件的第一行,则此行将被破坏。)

查找文件中具有多个匹配项的歧义标签并以上述方式(或其他想法)对其进行编辑,可以自动进行,每次tags文件被转换为后处理过程产生。但是,文件的附加扫描很昂贵;这确实应该在Ctags中完成。