我遇到的问题是 vim/gvim 中的 ctags 多次将我带到前向声明而不是函数的实际定义。
有什么办法可以解决吗?
我认为最简单的方法是使用“g ctrl-]”而不仅仅是“ctrl-]”。如果只有一场比赛,它会带你去那里。如果有多个匹配项,它会将它们全部列出,让您选择您想要的一个,就像 :tselect 一样。两全其美的。:)
我相信 Vim 默认会转到标签文件中的第一个标签。如果您愿意,您可以选择不同的:使用:tj
(类似于 :tselect,但如果只有一个匹配项则自动跳转)或Ctrl-]
后跟:tn
)。
更改默认值的唯一方法是更改标签文件的顺序,但我不相信 ctags 提供了命令行选项来执行此操作。
这并不像听起来那么难,因为您基本上需要一个脚本来打开标签文件,按标签的“种类”对其进行排序并再次将其写回。标签中的“种类”是单个字符,描述它是函数 (f)、函数原型 (p)、宏、枚举名称等等等。如果您使用的是 Linux,理论上它可以,简单到:
#!/bin/sh
ctags -R -f - . | tac > tags
由于tac
颠倒了文件中的行顺序,这将自动将定义放在首位。但是,由于需要维护标头并且 Vim 更喜欢对标记文件进行排序,所以它变得有点复杂,所以最好通过文件并按正序对第一个条目(标记名称)进行排序,然后种倒序。因此,更复杂的东西可能会更好。
我为这个无耻的插件道歉,但我已经写了一个 Vim 插件,它(间接地)做你需要的。它旨在为函数名称、宏、枚举等添加许多额外的突出显示组。但是,这样做的另一件事是重新排序标记文件,以便函数实现在函数声明之前,从而实现你想要的(我和你有同样的需要)。如果您不想要任何突出显示功能,您可以很容易地把它全部去掉:它是一个相当简单的 python 程序和一个更简单的 Vim 脚本,可以从我的网站获得。
您应该能够使用tn
并tp
跳转到各种匹配的标签。
^]
带您进入第一场比赛。:tn
以转到下一个。:tn
太多次,您可以键入:tp
返回到上一个。派对迟到了,但对于即将到来的 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>
这个选项对我更有效
将以下行放入您的 .vimrc 中,现在您可以使用鼠标双击(variable/entry
在您的文件中)跳转到标记的位置。如果找到单个匹配项,它将立即跳转。如果多个条目匹配,它将提示用户输入..
:map <2-LeftMouse> g< c-]>
将以下内容添加到您的 .vimrc 文件中:
noremap <c-]> 2<c-]>
这一行导致 vim 自动跳转到第二个匹配项(而不是第一个匹配项),这通常是函数定义。
: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)
匹配以 and 为锚点^
,$
并且由于前向声明以 结尾;
,因此不匹配。
但是,以下编码约定会触发该问题:
static int foo(
int x
);
static int foo(
int x
)
{
}
现在的tags
条目是:
foo foo.c /^static int foo($/;" f file: signature:( int x )
这将找到声明的第一行,这与定义的第一行没有区别。
解决方法是使这两者有所不同,同时保持编码约定。在这种情况下,我们在 C 中,所以我们可以做的一件事就是static
从定义中删除 the。
没有存储类说明符的 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 中完成。
你可以按2then CTRL+ ],这会直接进入第二个匹配,在java中,这通常是一些接口的实现。