繁体   English   中英

在 vim 中获取 ctags 以转到定义,而不是声明

[英]Get ctags in vim to go to definition, not declaration

我遇到的问题是 vim/gvim 中的 ctags 多次将我带到前向声明而不是函数的实际定义。

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

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

您应该能够使用tntp跳转到各种匹配的标签。

  • ^]带您进入第一场比赛。
  • 如果这不是您想要的匹配项,请键入:tn以转到下一个。
  • 如果您键入:tn太多次,您可以键入:tp返回到前一个。

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

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

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

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

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

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

迟到了,但对于传入的 vim 标签谷歌员工:

我发现在 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>

这个选项更适合我

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

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

你会得到一个匹配列表。 或者如果你跳到一个标签并且你对它不满意,然后输入

:tselect

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

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

您可以使用' tjump ' ex 命令。 例如,命令 ' :tjump func1 ' 将跳转到定义 func1,如果它只定义了一次。 如果多次定义 func1,则会显示匹配标签的列表。

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

您可以直观地选择一个文本并按g Ctrl-]来跳转或列出匹配的标签。

您可以使用“ stjump ”ex 命令。 这将在新窗口中从标签列表中打开匹配或选定的标签。

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

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

这可能是因为存储在标签文件中的模式匹配在定义之前找到了声明。

当 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

没有存储类说明符的 AC 文件范围声明声明了一个带有链接的名称。 链接类型(内部或外部)继承自任何先前指定链接的名称声明。 因此:

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 中完成。

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

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

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

你可以按2然后CTRL + ] ,这将直接进入第二个匹配,在java中,这通常是一些接口的实现。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM