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

发布于 2024-07-25 20:12:11 字数 76 浏览 5 评论 0原文

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

有办法解决这个问题吗?

I'm having the problem that ctags in vim/gvim takes me to a forward declaration a lot of times instead of to the actual definition of the function.

Any way to get around that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

狼亦尘 2024-08-01 20:12:12

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

I think that the easiest way is to use "g ctrl-]" instead of just "ctrl-]". If there is only one match, it will take you there. If there are multiple matches, it will list them all, letting you choose the one you want, just like :tselect. The best of both worlds. :)

李不 2024-08-01 20:12:12

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

  • ^] 将您带到第一场比赛。
  • 如果这不是您想要的匹配,请输入 :tn 转到下一个。
  • 如果您输入 :tn 次数过多,您可以输入 :tp 返回到上一次。

You should be able to use tn and tp to jump to the various matching tags.

  • Press ^] to take you to the first match.
  • If that's not the match you want, type :tn to go to the next.
  • If you typed :tn too many times you can type :tp to return to the previous one.
梦中的蝴蝶 2024-08-01 20:12:12

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

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

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

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

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

我为这个无耻的插件道歉,但我已经写了一个 Vim 插件,它(间接)可以满足你的需要。 它的目的是为函数名称、宏、枚举等添加大量额外的突出显示组。但是,它所做的其他事情之一是重新排序标记文件,以便函数实现位于函数声明之前,从而实现你想要的(我和你有同样的需求)。 如果您不需要任何突出显示功能,您可能可以轻松地将其全部删除:这是一个相当简单的 python 程序和一个更简单的 Vim 脚本,可以从 我的网站

I believe Vim goes to the first tag in the tags file by default. You can select a different one if you prefer: use :tj (similar to :tselect, but auto-jump if there's only one match) or Ctrl-] followed by :tn).

The only way of changing the default is to change the order of the tags file, but I don't believe ctags offers a command-line option to do this.

This isn't as hard as it sounds as you basically need a script that opens the tags file, sorts it by the 'kind' of tag and writes it back out again. The 'kind' in the tag is a single character describing whether it's a function (f), a function prototype (p), a macro, a enumerated name etc etc etc. If you're using Linux, it could, in theory, be as simple as:

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

Since tac reverses the order of lines in a file, this will automatically put the definition first. However, it gets a bit more complicated as the header needs to be maintained and Vim prefers the tag file to be sorted, so it's better to go through the file and sort on the first entry (the tag name) in forward order and then the kind in reverse order. Therefore, something more complicated may be better.

I apologise for the shameless plug, but I have written a Vim plugin that (indirectly) does what you need. It is intended for adding lots of extra highlighting groups for things like function names, macros, enums etc. However, one of the other things that this does is re-sort the tag file so that the function implementation comes before the function declaration, thereby achieving what you want (I had the same need as you). If you don't want any of the highlighting functionality, you could probably strip it all out quite easily: it's a fairly simple python program and an even simpler Vim script and is available from my site.

鯉魚旗 2024-08-01 20:12:12

虽然迟到了,但对于即将到来的 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>

Late to the party, but for incoming vim tag googlers:

I've found that using cscope in addition to ctags is the way to go, at least for C/C++. It's more intelligent about call trees, and you can set it to fallback to ctags if it fails. Just run "cscope -b" everytime you run ctags -R . and you'll be ready to go. If you use the settings below, you'll be able to use Ctrl-]/Ctrl-T like always, but you can also add nifty new jumps like jumping to a function declaration and showing a jumplist of function callers.

" 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>
绝對不後悔。 2024-08-01 20:12:12

这个选项对我来说效果更好

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

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

This option worked for me better

Put the following line in your .vimrc and now you can use double click of the mouse (on the variable/entry in your file) to jump to the tagged location. If single match is found, it will jump right away. If multiple entries are matches, it will prompt for user input..

:map <2-LeftMouse> g< c-]>
岁月染过的梦 2024-08-01 20:12:12

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

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

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

Add the following to your .vimrc file:

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

This line causes vim to automatically jump to the second match (instead of the first one), which is usually the function definition.

若水微香 2024-08-01 20:12:12
:tselect my_little_function 

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

:tselect

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

:tselect my_little_function 

and you would get a list of matches.
or if you jump to a tag and you are not happy with it, then type

:tselect

And you get a list of alternative for the last active tag.

可是我不能没有你 2024-08-01 20:12:12

有几种方法可以让 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-]

There are several ways to make Vim to jump to a tag directly, if there is only one tag match, otherwise present a list of tag matches.

You can use the 'tjump' ex command. For example, the command ':tjump func1' will jump to the definition func1, if it is defined only once. If func1 is defined multiple times, a list of matching tags will be presented.

You can position the cursor over the tag and press g Ctrl-].

You can visually select a text and press g Ctrl-] to jump or list the matching tags.

You can use the 'stjump' ex command. This will open the matching or selected tag from the tag list in a new window.

You can press Ctrl-W g Ctrl-] to do a :stjump.

Help: :tjump, g_Ctrl-], v_g_CTRL-], :stjump, Ctrl-W_g_Ctrl-]
何时共饮酒 2024-08-01 20:12:12

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

当 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)

匹配通过 ^ 和 < 进行锚定code>$,并且由于前向声明以 ; 结尾,因此不匹配。

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

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

This can happen because the pattern match stored in the tags file finds the declaration before the definition.

When Exuberant Ctags creates an entry for an identifier, it adds the entire containing line as a match.

However, sometimes the forward declaration matches that pattern. This can happen under certain coding styles.

First, here is an example file, foo.c which doesn't have this problem:

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

Ctags creates an entry which looks like this:

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

The match is anchored with ^ and $, and since the forward declaration ends with ;, it does not match.

However, the following coding convention triggers the issue:

static int foo(
 int x
);

static int foo(
  int x
)
{
}

The tags entry is now:

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

This will find the first line of the declaration, which is indistinguishable from the first line of the definition.

The fix is to make these two somehow different, while staying within the coding convention. In this case we are in C, so one thing we can do is drop the static from the definition.

A C file scope declaration that has no storage class specifier declares a name with linkage. The linkage type (internal or external) is inherited from any previous declaration of the name that specified linkage. Thus:

static int foo(
 int x
);

int foo(
  int x
)
{
}

And now the tag looks like:

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

which matches only the definition; Vim no longer jumps to the first declaration.

If this solution is not workable, then it may be necessary to write a tags filtering tool which scans the tags file and identifies this problem, fixing up the offending tags. For example, for the second file with the ambiguous lines, we can fix up the tag manually like this:

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

I added a second Ex command into the tag-address, to search for the same pattern again. Now it jumps to the correct line. (Note: however, this is broken if the forward declaration is the very first line of the file.)

Finding ambiguous tags which have more than one match in the file and editing them in the above manner (or some other idea) can be automated, turned into a post-processing pass done each time the tags file is generated. The additional scan of the files is expensive, though; this really should be done in Ctags.

鹊巢 2024-08-01 20:12:12

如果您使用 fzf(为什么不呢?),请尝试以下操作 - 一种 ctags 类固醇跳跃......

" FZF search tags
function s:ZTags()
  " Get current (whole!) word
  let l:text = expand("<cword>")
  if l:text ==# ''
    let l:text = ''
  endif

  exe 'ZTags '.l:text
endfunction

" Find the tag under the cursor
nnoremap <silent> <S-T> :call <sid>ZTags()<cr>

If you use fzf (and why wouldn't you?), try the following - a sort of ctags jump on steroids...

" FZF search tags
function s:ZTags()
  " Get current (whole!) word
  let l:text = expand("<cword>")
  if l:text ==# ''
    let l:text = ''
  endif

  exe 'ZTags '.l:text
endfunction

" Find the tag under the cursor
nnoremap <silent> <S-T> :call <sid>ZTags()<cr>
撩起发的微风 2024-08-01 20:12:12

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

You can press 2 then CTRL+], this will go directly to the second match, in java, this is usually the implementation of some interface.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文