我遇到的问题是vim / gvim中的ctags很多时候都会转发前向声明而不是函数的实际定义。
有什么方法可以解决这个问题吗?
答案 0 :(得分:70)
我认为最简单的方法是使用“g ctrl-]”而不是“ctrl-]”。如果只有一场比赛,它会带你到那里。如果有多个匹配项,它会将它们全部列出,让您选择所需的匹配项,如:tselect。两全其美的。 :)
答案 1 :(得分:9)
您应该可以使用tn
和tp
跳转到各种匹配的代码。
^]
转到第一场比赛。: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中完成。