tag tags
标签是出现在 "tags" 文件的一个标识符。它是一种能够跳转的标记。例如,在 C 程序
里,每个函数名都可以是一个标签。在使用标签文件之前,"tags" 文件由 ctags 这样的
程序生成。
使用 ":tag" 命令移动光标到标签上。使用 CTRL-]
命令,光标所在的关键字就可用作标
签。如果光标不在关键字上,则使用最右侧的一个关键字。
":tag" 命令对 C 程序十分有效。如果你看到一个函数的调用而想知道该函数的作用,把
光标移动到函数名上,并按 CTRL-]
。它会把你带到该函数的定义上。简单的,按 CTRL-T
就可以回去。同时,也请阅读下面关于标签栈的描述。
:ta :tag E426 E429
:[count]
ta[g][!] {name}
根据 tags 文件的信息,跳转到 {name}
的定义上。
把 {name}
放在堆栈上。[!] 见 tag-! 。
{name}
可以是正则表达式。见 tag-regexp 。
如果有 {name}
的多个匹配,则跳转到它们中的第 [count]
个。如果 [count]
被省略,则跳转到第一个。要跳转到其它
匹配的标签,参见 tag-matchlist 。
g<LeftMouse>
g<LeftMouse>
<C-LeftMouse>
<C-LeftMouse> CTRL-]
CTRL-]
跳转到光标所在的关键字的定义。和 ":tag {name}
" 相同,
只不过 {name}
是光标之下或者之后的关键字。
如果有 {name}
的多个匹配,则跳转到它们中的第 [count]
个。如果没有 [count]
,跳转到第一个。 要跳转到其它匹配
的标签,参见 tag-matchlist 。
v_CTRL-]
{Visual}
CTRL-]
和 ":tag {name}
" 相同,其中 {name}
是高亮的文本。
telnet-CTRL-]
CTRL-]
是缺省的 telnet 转义键。在你按 CTRL-]
进行标签跳转的时候,你会得到
telnet 的提示符。许多版本的 telnet 允许你改变或者屏蔽缺省的转义键。见 telnet
的手册页。你可以用 'telnet -E {Hostname}
' 来屏蔽转义键,或者用 'telnet -e
{EscapeCharacter}
{Hostname}
' 来指定别的转义键。如果可能,用 "ssh" 来代替
"telnet" 也可解决这个问题。
tag-priority
如果有标签的多个匹配,使用以下的优先级:
1. "FSC" 当前文件的完整的匹配静态标签。
2. "F C" 当前文件的完整匹配全局标签。
3. "F " 其他文件的完整匹配全局标签。
4. "FS " 其他文件的完整匹配静态标签。
5. " SC" 当前文件的忽略大小写的匹配静态标签。
6. " C" 当前文件的忽略大小写匹配全局标签。
7. " " 其他文件的忽略大小写匹配全局标签。
8. " S " 其他文件的忽略大小写匹配静态标签。
注意
当前文件改变时,优先顺序多数情况下不会改变,以免使 ":tnext" 的使用引起混
淆。在使用 ":tag {name}
" 时,优先顺序才会改变。
以下情况下,":tag" 命令不会查找忽略大小写的匹配:
- 'tagcase' 为 "followic" 且 'ignorecase' 选项关闭
- 'tagcase' 为 "followscs" 且 'ignorecase' 选项关闭且 'smartcase' 选项关闭或模
式包含大写字符。(译者注
: 原文如此,似不确)
- 'tagcase' 为 "match"
- 'tagcase' 为 "smart" 且模式包含大写字符。
以下情况下,查找忽略大小写的匹配:
- 使用模式 (以 "/" 开始)
- ":tselect"
- 'tagcase' 为 "followic" 且 'ignorecase' 打开
- 'tagcase' 为 "followscs" 且 'ignorecase' 打开或 'smartcase' 选项打开且模式不
包含大写字符 (译者注
: 原文如此,似不确)
- 'tagcase' 为 "ignore"
- 'tagcase' 为 "smart" 且模式不包含大写字符
注意
使用忽略大小写查找就无法应用 tags 文件的二分法查找,从而减慢了查找速度。
这可以用大小写合并排序的标签文件来解决。具体解释见 'tagbsearch' 选项。
标签栈记住你跳转过的标签,还有从哪里跳转到这些标签。只有在设置 'tagstack' 选项
的时候,标签才被压到堆栈里。
g<RightMouse>
g<RightMouse>
<C-RightMouse>
<C-RightMouse> CTRL-T
CTRL-T
跳到标签栈上第 [count]
个较早的项目 (缺省为 1)。
:po :pop E555 E556
:[count]
po[p][!] 跳到标签栈上第 [count]
个较早的项目 (缺省为 1)。
[!] 见 tag-! 。
:[count]
ta[g][!] 跳到标签栈上第 [count]
个较新的项目 (缺省为 1)。
[!] 见 tag-! 。
:tags
:tags 显示标签栈的内容。激活的项目以 '>' 标明。
":tags" 的输出结果类似于:
# TO tag FROM line in file/text
1 1 main 1 harddisk2:text/vim/test
> 2 2 FuncA 58 i = FuncA(10);
3 1 FuncC 357 harddisk2:text/vim/src/amiga.c
该列表显示你跳转到的标签和跳转前光标的位置。较早的项目在顶部,较新的在底部。
'>' 指向活动的项目。这是下一个 ":tag" 命令将使用的标签。CTRL-T
和 ":pop" 使用
活动项目之上的那项的位置。
"TO" 之下的那列显示匹配表的当前匹配的数目。注意
这不会因为使用 ":pop" 或者
":tag" 而改变。
记住文件名和行号可以使你回到 tag 命令之前的位置。即使你删除或者插入行,行号也
会保持正确,除非你用别的程序 (比如,另外一个 Vim 的实例) 做这些事。
对于当前文件,"file/text" 列显示该位置的文本。缩进被删除,长行也被截短,以便能
放进窗口里显示。
有若干命令可以让你跳到之前用过的标签。一些例子包括:
":pop" 或 CTRL-T
到上一个标签之前的位置
{count}
CTRL-T
到第 {count}
个较早的标签之前的位置
":tag" 到更新的标签
":0tag" 到前一个使用过的标签
最明显的应用就是浏览程序的调用图。考虑下面的调用图:
main ---> FuncA ---> FuncC
---> FuncB
(解释: main 调用 FuncA 和 FuncB; FuncA 调用 FuncC)。
从 main 到 FuncA,你可以在调用 FuncA 的行上用 CTRL-]
。然后再用 CTRL-]
跳到
FuncC。如果你现在想跳回到 main,你只需要按 CTRL-T
两次。然后你可以用 CTRL-]
到
FuncB。
如果你使用 ":ta {name}
" 或者 CTRL-]
命令,该标签被加在栈的当前位置。如果栈已满
(最多可以容纳 20 项),最早的项目被删除,较早的项目则依次前移 (索引号分别减
1)。如果最近使用的项目不在底部,它其后的项目都被删除。这意味着调用图上的旧的分
支丢失了。在上面解释的命令执行以后,标签栈看起来像这样:
# TO tag FROM line in file/text
1 1 main 1 harddisk2:text/vim/test
2 1 FuncB 59 harddisk2:text/vim/src/main.c
gettagstack() 函数返回指定窗口的标签栈。 settagstack() 函数修改窗口的标签
栈。
tagstack-examples
像 :tag 那样写入标签栈,但用用户自定义的 jumper#jump_to_tag 函数:
" 跳转前,先保存当前位置。
let tag = expand('<cword>')
let pos = [bufnr()] + getcurpos()[1:]
let item = {'bufnr': pos[0], 'from': pos, 'tagname': tag}
if jumper#jump_to_tag(tag)
" 跳转成功,把之前的位置写入标签栈。
let winid = win_getid()
let stack = gettagstack(winid)
let stack['items'] = [item]
call settagstack(winid, stack, 't')
endif
设置标签栈的当前索引为 4:
call settagstack(1005, {'curidx' : 4})
给标签栈压入新项目:
let pos = [bufnr('myfile.txt'), 10, 1, 0]
let newtag = [{'tagname' : 'mytag', 'from' : pos}]
call settagstack(2, {'items' : newtag}, 'a')
E73
如果你试图使用标签栈,而其中没有任何内容,你会得到一个错误信息。
如果有多个匹配的标签,这些命令可以用来在它们之间跳转。注意
这些命令不影响标签
栈,它保留原来的项目。
:ts :tselect
:ts[elect][!] [name]
根据 tags 文件的信息,列出匹配 [name]
的标签。
如果 [name]
没有给出,使用标签栈上最后的标签名。
关于 [!] 见 tag-! 。
第一列的 '>' 指示列表的当前位置 (如果有的话)。
[name]
可以是正则表达式,见 tag-regexp 。
列表使用的优先级顺序见 tag-priority 。
示例输出:
# pri kind tag file
1 F f mch_delay os_amiga.c
mch_delay(msec, ignoreinput)
> 2 F f mch_delay os_msdos.c
mch_delay(msec, ignoreinput)
3 F f mch_delay os_unix.c
mch_delay(msec, ignoreinput)
Type number and <Enter> (empty cancels):
"pri" 列见 tag-priority 。注意
这决定于当前文件,因而
":tselect xxx" 可能会输出不同的结果。
如果 tags 文件给出标签的类型。"kind" 列输出此信息。
"info" 列给出 tags 文件找到的信息。这决定于产生 tags
文件的程序。
如果列表很长,你可能会看到 more-prompt 。如果你已经看
到要用的标签,按 'q' 并输入那个数字。
:sts :stselect
:sts[elect][!] [name]
":tselect[!] [name]
" 并分割窗口以显示选择的标签。
g]
g] 类似于 CTRL-]
,但使用 ":tselect" 而不是 ":tag"。
v_g]
{Visual}
g] 和 "g]" 相同,但使用高亮文本作为标识符。
:tj :tjump
:tj[ump][!] [name]
类似于 ":tselect",但如果只有一个匹配,直接跳转之。
:stj :stjump
:stj[ump][!] [name]
":tjump[!] [name]
" 并分割窗口以显示选择的标签。
g_CTRL-]
g CTRL-]
类似于 CTRL-]
,但使用 ":tjump" 而不是 ":tag"。
v_g_CTRL-]
{Visual}
g CTRL-]
和 "g CTRL-]
" 相同,但使用高亮文本作为标识符。
:tn :tnext
:[count]
tn[ext][!] 跳转到向下 [count]
个匹配的标签 (缺省为 1)。[!] 见
tag-! 。
:tp :tprevious
:[count]
tp[revious][!] 跳转到向上 [count]
个匹配的标签 (缺省为 1)。[!] 见
tag-! 。
:tN :tNext
:[count]
tN[ext][!] 和 ":tprevious" 相同。
:tr :trewind
:[count]
tr[ewind][!] 跳转到第一个匹配的标签。如果给出 [count]
,跳到第
[count]
个匹配的标签。[!] 见 tag-! 。
:tf :tfirst
:[count]
tf[irst][!] 和 ":trewind" 相同。
:tl :tlast
:tl[ast][!] 跳到最后匹配的标签。[!] 见 tag-! 。
:lt :ltag
:lt[ag][!] [name]
跳转到标签 [name]
上并在当前窗口的新位置列表中加入匹
配的标签。
[name]
可以是正则表达式,见 tag-regexp 。如果
[name]
没有给出,使用标签栈上最后的标签名。查找标签行
的搜索模式会加上 "\V" 前缀,转义所有的特殊字符 (very
nomagic)。显示匹配标签的位置列表独立于标签栈。[!] 见
tag-! 。
如果没有其他消息,Vim 显示跳到的是哪个匹配的标签,还有匹配标签的总数:
tag 1 of 3 or more
" or more" 用于说明 Vim 并没有尝试完所有的 tags 文件。多用几次 ":tnext" 或者用
":tlast" 也许会找到更多。
如果因为有其他的消息使得你没看到这个消息,或者你想知道现在在哪里,以下这个命令
会再次显示本消息 (并跳转到最近一次的相同的标签):
:0tn
tag-skip-file
如果找到一个匹配的标签,但是相应的文件却不存在,该匹配被跳过,而使用下一个匹
配。Vim 报告这一点,提醒你文件的丢失。在匹配列表的结束处,会给出错误。
tag-preview
标签匹配表也可用在预览窗口。命令和上面一样,除了前面有个 "p"。
{仅当编译时加入 +quickfix 特性才有效}
:pts :ptselect
:pts[elect][!] [name]
":tselect[!] [name]
" 并在预览窗口显示新的标签。详情见
:ptag 。
:ptj :ptjump
:ptj[ump][!] [name]
":tjump[!] [name]
" 并在预览窗口显示新的标签。详情见
:ptag 。
:ptn :ptnext
:[count]
ptn[ext][!] 在预览窗口里 ":tnext"。见 :ptag 。
:ptp :ptprevious
:[count]
ptp[revious][!] 在预览窗口里 ":tprevious"。见 :ptag 。
:ptN :ptNext
:[count]
ptN[ext][!] 同 ":ptprevious"。
:ptr :ptrewind
:[count]
ptr[ewind][!] 在预览窗口中 ":trewind"。见 :ptag 。
:ptf :ptfirst
:[count]
ptf[irst][!] 同 ":ptrewind"。
:ptl :ptlast
:ptl[ast][!] 在预览窗口中见 ":tlast"。见 :ptag 。
static-tag
静态标签是为特定文件定义的标签。在 C 程序里,这可能是一个静态函数。
Vi 里跳转某个标签的同时设置当前搜索模式。这意味着在标签跳转后,"n" 命令不再查
找跳转前最后使用的模式了。Vim 没有这么做,因为我们认为这是一个错误。如果你真的
想要从前 Vi 那样的行为,在 'cpoptions' 里设置 't' 标志位。
tag-binary-search
Vim 使用二分法查找标签文件,以快速查找到希望找到的标签 (如果编译时打开
+tag_binary 特性的话)。不过这只有在 tags 文件按 ASCII 字节值排序才有效。因
此,如果没有匹配,Vim 会按照线性查找再来一次。如果你只想要线性查找。复位
'tagbsearch' 选项。或者更好的: 对 tags 文件排序!
注意
如果不查找特定名字,标签的查找不使用二分法查找。这包括忽略大小写的查找或
不以固定字符串开始的正则表达式的查找。这样的标签搜索可能会慢很多。前者可以用大
小写合并排序来解决。详情见 'tagbsearch'。
tag-regexp
":tag" 和 ":tselect" 命令接受正则表达式参数。 pattern 可以看到如何使用特别的
字符。如果参数以 '/' 开始,它被认为是一个模式。如果不是,它被认为是按本义出现
的完整的标签名。
示例:
:tag main
跳转到最高优先级的 "main" 标签。
:tag /^get
跳转到最后优先级的 "get" 开始的标签。
:tag /norm
列出所有包含 "norm" 的标签,例如 "id_norm"。
如果参数既能按本义匹配,也能按正则表达式匹配,本义匹配有更高的优先级。比如,
":tag /open" 在 "open_file" 和 "file_open" 之前匹配 "open"。
如果使用模式,那么忽略大小写。如果你想在模式中匹配大小写,使用 "\C"。
tag-!
如果标签在当前文件里,没有问题。不然,采取的行动取决于当前文件是否有改变,还有
命令之后是否加了 !,以及 'autowrite' 选项:
标签是否在 文件是 autowrite
当前文件里 否改变 ! 选项 行动
是 x x x 转到标签
否 否 x x 读入其他文件,转到标签
否 是 是 x 放弃当前文件,读入其他文件,转到标签
否 是 否 开 写入当前文件,读入其他文件,转到标签
否 是 否 关 失败
- 如果标签在当前文件里,该命令总能工作。
- 如果标签在另外的文件里而当前文件没有改变。那个文件成为当前文件,并读入到缓冲
区里。
- 如果标签在另外的文件里而当前文件发生了改变。而命令后加了 !,那么当前文件的改
变被放弃,那个文件成为当前文件,并读入缓冲区。
- 如果标签在另外的文件里而当前文件发生了改变。而 'autowrite' 选项被打开,那么
当前文件的改变被保存,那个文件成为当前文件,并读入缓冲区。
- 如果标签在另外的文件里而当前文件发生了改变。而 'autowrite' 选项被关闭,那么
该命令失败。此时,如果你想保存改变,先用 ":w" 命令,再用不带参数的 ":tag"。
这是因为标签已经在堆栈上了。如果你想放弃改变,你可以用 ":tag!" 命令。
tag-security
注意
Vim 为了安全原因禁止某些命令。这类似于在当前目录下的 exrc/vimrc 文件里使
用了 'secure' 选项。见 trojan-horse 和 sandbox 。
如果 {tagaddress}
改变了缓冲区,你会得到警告
:
"WARNING: tag command changed a buffer!!!"
在将来的版本里,也许会禁止对缓冲区的改变。这些都是为了安全原因: 有的人可能在
tags 文件里隐藏了恶意的命令。如果不这么做,你也许不能看到这一点。例如:
:$d|/tag-function-name/
Vi 里跳转某个标签的同时设置当前搜索模式。Vim 没有这么做,以前的搜索模式还是记
住的。除非 'cpoptions' 里设置了 't' 标志位。
emacs-tags emacs_tags E430
Emacs 风格的 tag 文件只有在 Vim 编译的时候加入 +emacs_tags 特性时才有效。对
不起,这里没有 Emacs 标签文件的解释,支持它只是为了后向兼容。:-)。
Emacs 标签文件的行可能很长。Vim 只处理不超过 510 字节的行。要看到哪些行被忽
略,设置 'verbose' 为 5 或更高。非 Emacs 的标签文件行接受任何长度。
tags-option
'tags' 选项是文件名的列表。其中的每个文件都用来搜索标签。这可以用来指定不同于
缺省的 "tags" 文件的标签文件。它也可以用来访问一个公用的标签文件。
下列情况下,不再查找列表中的下个文件:
- 找到了当前缓冲区的匹配的静态标签。
- 找到了全局标签。
同时也取决于是否忽略大小写。以下条件下忽略大小写:
- 'tagcase' 为 "followic" 并且置位 'ignorecase'
- 'tagcase' 为 "ignore"
- 'tagcase' 为 "smart" 且模式只包含小写字符。
- 'tagcase' 为 "followscs" 且置位 'smartcase' 且模式只包含小写字符。
如果不忽略大小写,而当前标签文件找到大小写不符合的匹配,那么就会查找下一个文
件。如果没有匹配大小写的标签,则使用第一个大小写不符合的匹配。如果忽略大小写,
而找到全局的匹配 (不论大小写),则立即使用之,而无须继续查找下一个文件。
如果标签文件以 "./" 开始,则 '.' 会被替代成当前的文件所在的路径。这样,你可以
使用当前文件所在的目录下的标签文件 (无论当前目录在哪里)。使用 "./" 的逻辑是,
你可以定义哪个标签文件最先查找: 先当前目录 ("tags,./tags"),还是先当前文件所处
的目录 ("./tags,tags")。
例如:
:set tags=./tags,tags,/home/user/commontags
在这个例子里,先查找当前文件所处目录的 "tags" 文件。再查找当前目录下的 "tags"
文件。如果没有,再查找 "/home/user/commontags"。
要 Vi 兼容,可以在 'cpoptions' 里包含 'd' 标志位。这样,"./tags" 会是当前目录
下的 tags 文件,而不是当前文件所在的目录下的。
除了逗号以外,也可以用空格。而在字符串值的选项里,空格需要用反斜杠转义:
:set tags=tags\ /home/user/commontags
这样,要在文件名里包含空格,需要三个反斜杠。要在文件名里包含逗号,需要两个反斜
杠。例如,可以用:
:set tags=tag\\\ file,/home/user/common\\,tags
来指定文件 "tag file" 和 "/home/user/common,tags"。'tags' 选项会包含值
"tag\ file,/home/user/common\,tags"。
如果打开 'tagrelative' 选项 (这是缺省值) 而使用别的目录的标签文件,该标签文件
所引用的文件名相对于标签文件本身所处的目录。
ctags jtags
标签文件是外部程序创建的,比如 "ctags"。对每个函数,它会包含一个标签。有些版本
的 "ctags" 会为每个 "#define" 宏、类型等价定义 (typedef)、枚举 (enum) 等也创建
标签。
能产生标签文件的程序有:
ctags 大多数 Unix 系统都能找到。只支持 C。只有基本的功能。
universal ctags 基于 exuberant ctags 的 ctags 维护版本。参见
https://ctags.io。
Exuberant_ctags
exuberant ctags 这是很好的一个。它支持 C、C++、Java、Fortran、Eiffel
等等。它能为很多项目产生标签。见
http://ctags.sourceforge.net。
2009 年后没有新版本。
etags 和 Emacs 有关。支持很多语言。
JTags 用 Java 编写,为 Java 而设计。可以在这里找到:
http://www.fleiner.com/jtags/。
ptags.py 用 Python 编写,为 Python 而设计。它位于你的 Python 源
代码目录 Tools/scripts/ptags.py。
ptags 用 Perl 编写,为 Perl 而设计。可以在这里找到:
http://www.eleves.ens.fr:8080/home/nthiery/Tags/。
gnatxref 为 Ada 而设计。见 http://www.gnuada.org/。gnatxref 是
gnat 包的一部分。
标签文件的行应是以下两种格式之一:
1. {tagname}
{TAB}
{tagfile}
{TAB}
{tagaddress}
2. {tagname}
{TAB}
{tagfile}
{TAB}
{tagaddress}
{term}
{field}
..
之前支持一种旧格式。见 tag-old-static 。
第一种格式是普通的标签,和 Vi 完全兼容。传统的 ctags 实现只能产生这种格式。通
常,这用于被别的文件所引用的全局函数,
标签文件行可以用 <NL>
或者 <CR>
<NL>
结尾。在 Macintosh 上,<CR>
也能工作。<CR>
和 <NL>
字符不应该在行内出现。
第二个格式是新出现的。它在每行尾部的可选字段上包含了附加的信息。它和 Vi 后向兼
容。只有新的 ctags 版本 (比如 Universal ctags 或 Exuberant ctags) 才支持这种格
式。
{tagname}
标识符。通常是函数的名字,但可以是任何标识符。不能包含 <Tab>
。
{TAB}
单个 <Tab>
字符。注意
: 以前的版本允许任意多个空白字符。现在不
支持,因为 {tagfile}
里可能包含空格。
{tagfile}
包含 {tagname}
定义的文件。可以是绝对路径或者相对路径。还可以
包含环境变量甚至通配符 (尽管使用通配符很值得怀疑)。它不能包含
<Tab>
。
{tagaddress}
可以定位到 tag 的光标位置的 Ex 命令。可以是任何 Ex 命令,尽管
有一些限制 (见 tag-security )。Posix 只允许行号和搜索命令,这
也是最常用的。
{term}
;" 分号和双引号两个字符。这被 Vi 解释为注释的开始,从而忽略其
后的部分。这样,就能和 Vi 后向兼容,因为 Vi 忽略后面的字段。例
如:
APP file /^static int APP;$/;" v
如果 {tagaddress}
不是行号或搜索模式,{term}
必须是 |;"。这里
的竖线结束命令 (不包含竖线),而 ;" 使 Vi 忽略行的其它部分。例
如:
APP file.c call cursor(3, 4)|;" v
{field}
.. 可选的字段列表。每个字段有以下形式:
<Tab>
{fieldname}
:{value}
{fieldname}
标识字段,并且只能包含字母 [a-zA-Z]。
{value}
可以使任何字符串,但不能包含 <Tab>
。
以下字符有特殊含义:
"\t" 代表 <Tab>
"\r" 代表 <CR>
"\n" 代表 <NL>
"\\" 代表单个 '\' 字符
有一个字段不需要 ':'。那就是标签的类型。它的处理方式就像前面
有 "kind:" 开头那样。ctags 能产生的类型见它的文档。
唯一的 Vim 能识别的其他字段是 "file:" (带一个空值)。用于静态变
量。
标签文件的开头可以包含这样开始的行:
!_TAG_
排序以后,他们一般都排在最前面。只有很少的以 "!" 开头的标签能排在他们前面。Vim
识别两项。第一个是指示文件是否排序的标志。如果找到这么一行,Vim 使用二分法查找
标签文件:
!_TAG_FILE_SORTED<Tab>
1<Tab>
{anything}
标签文件可以按大小写合并排序,以免忽略大小写时只能进行线性查找 ('ignorecase'
置位且 'tagcase' 为 "followic" 或 'tagcase' 为 "ignore" 时忽略大小写)。详情见
'tagbsearch'。这时可以用值 2:
!_TAG_FILE_SORTED<Tab>
2<Tab>
{anything}
另一个 Vim 识别的标签指定标签文件的编码:
!_TAG_FILE_ENCODING<Tab>
utf-8<Tab>
{anything}
这里 "utf-8" 是标签们所用的编码。Vim 会把查找的标签从 'encoding' 转为标签文件
的编码。当列出标签时,则反之。如果转换失败,则直接使用未经转换的标签。
tag-search
标签搜索命令可以是任何 Ex 命令,但通常就是普通的搜索命令。比如:
tag1 file1 /^main(argc, argv)/
tag2 file2 108
该命令执行时总假设不设定 'magic'。搜索模式里仅有的特别的字符是 "^" (行首) 和
"$" (<EOL>
)。见 pattern 。注意
,你必须在搜索文本里的每个反斜杠前加上反斜杠。
这和 Vi 反向兼容。
E434 E435
如果该命令是一个普通的搜索命令 (也就是,以 "/" 或 "?" 开头和结尾),会进行一些
特殊处理:
- 搜索从文件第 1 行开始。
如果用 "/",搜索方向为正向,"?" 则为反向。
注意
'wrapscan' 没有影响,总是搜索整个文件。
- 如果搜索失败,忽略大小写再重新尝试一次。如果还不行,搜索:
"^tagname[ \t]*("
(实际的标签前面加上 '^' 而后面加上 "[ \t]*(")。应用函数名的时候,它会找到在
第 0 列的函数名。这会有助于找到该函数,即使它的参数和生成 tags 文件时有差
异。如果还不行,进行另外一个搜索:
"^[#a-zA-Z_].*\<tagname[ \t]*("
这意味着: 以 '#' 或者一个标识符开始的一行,包含标签本身,后面紧跟空白和一个
'('。这会找到宏名和前面有返回类型的函数名。
tag-old-static
直到 2019 年 3 月 (8.1.1092 补丁) 为止,曾经支持过另一种过时的格式:
{tagfile}
:{tagname}
{TAB}
{tagfile}
{TAB}
{tagaddress}
这种格式只限于静态标签。现在已经废弃了,被第二种格式取而代之。只有 Elvis 1.x,
旧版的 Vim 还有很少的 ctags 版本支持。静态变量用于本地函数,只有文件 {tagfile}
才引用。注意
对静态变量而言,{tagfile}
的两次出现必须完全一致。关于如何使用静
态变量,见下面的 tags-option 。
删除了此支持,因为你既然可以更新 Vim 版本,也应可以更新 ctags 以支持第二种格
式。
E387 E388 E389
这些命令递归地查找当前文件和所有遇到的头文件的一个字符串。这可以用来查找变量的
定义,函数或者宏。如果只想查找当前缓冲区,用 pattern-searches 列出来的命令。
这些命令只有在编译时加入 +find_in_path 特性才会有效。
如果一个文件的某行包含另一个文件,那么那个文件在当前缓冲区继续之前先进行搜索。
头文件里包含的头文件也会被搜索。当头文件找不到时,它被悄悄地忽略掉。用
:checkpath 命令检查哪些文件可能找不到。是不是因为你的 'path' 选项没有设对。
注意
: 被搜索的是头文件本身,不是可能正在编辑它的缓冲区。只有当前的文件除外,它
使用缓冲区里的行。
字符串可能是任何的关键字或者定义的宏。对于关键字,任何匹配都会找到。对于定义的
宏,只有用匹配 'define' 选项的行才会被找到。它的缺省值是 "^#\s*define"。这对 C
程序适用,对于其它语言你可能想改变之。C++ 的一个例子见 'define'。该字符串不能
包含换行符,只能匹配一行之内的文本。
如果找到一个定义的宏的匹配,并且该行以反斜杠结尾的话。行的显示在下一行继续。
"[" 开头的命令从当前文件开始查找。"]" 开始的命令从当前光标位置开始。
'include' 选项用于定义可以包含另一个文件的行。缺省是 "\^#\s*include"。它适用于
C 程序。注意
: Vim 并不试图识别 C 语法。如果 'include' 选项在 #ifdef/#endif 之
间或者注释内的一行上匹配,它也会被搜索到。'isfname' 选项用于识别匹配之后的文件
名。
'path' 选项用于查找不含绝对路径的头文件所在的目录。
'comments' 选项用来显示或者跳转到一行的命令。如果定义的模式可能包含注释,这些
行用来跳过搜索,除非使用 [!]。一个特例: 如果一行匹配模式 "^# *define",它不会
被认为是注释。
如果你想列出所有的匹配,然后选择一个并跳转之,你可以使用一个映射来做这件事。这
里是一个例子:
:map <F4> [I:let nr = input("Which one: ")<Bar>exe "normal " .. nr .. "[\t"<CR>
[i
[i 显示第一个包含光标所在的关键字的行。搜索从文件开头开
始。看起来像注释的行被忽略 (见 'comments' 选项)。如果
给出一个计数,跳转到第 count 个匹配的行,注释行不忽
略。
]i
]i 类似于 "[i",但是从当前光标位置开始。
:is :isearch
:[range]
is[earch][!] [count]
[/]pattern[/]
类似于 "[i" 和 "]i",但在 [range]
行范围搜索 (缺省: 整
个文件)。
关于 [/] 和 [!] 见 :search-args 。
[I
[I 显示包含光标下的关键字的所有的行。找到的每行都显示文件
名和行号。搜索从文件头开始。
]I
]I 类似于 "[I",但是从当前光标位置开始。
:il :ilist
:[range]
il[ist][!] [/]pattern[/]
类似于 "[I" 和 "]I",但在 [range]
行范围搜索 (缺省:
整个文件)。
关于 [/] 和 [!] 见 :search-args 。
[_CTRL-I
[ CTRL-I
跳转到第一个包含光标所在的关键字的行。搜索从文件开头开
始。看起来像注释的行被忽略 (见 'comments' 选项)。如果
给出一个计数,跳转到第 count 个匹配的行,注释行不忽
略。
]_CTRL-I
] CTRL-I
类似于 "[ CTRL-I
",但是从当前光标位置开始。
:ij :ijump
:[range]
ij[ump][!] [count]
[/]pattern[/]
类似于 "[ CTRL-I
" 和 "] CTRL-I
",但在 [range]
行范围
搜索 (缺省: 整个文件)。
关于 [/] 和 [!] 见 :search-args 。
CTRL-W
CTRL-I
CTRL-W_CTRL-I CTRL-W_i
CTRL-W
i 打开一个新窗口,把光标放在第一个包含光标所在的关键字的
行。搜索从文件开头开始。看起来像注释的行被忽略 (见
'comments' 选项)。如果给出一个计数,跳转到第 count 个
匹配的行,注释行不忽略。
:isp :isplit
:[range]
isp[lit][!] [count]
[/]pattern[/]
类似于 "CTRL-W
i" 和 "CTRL-W
i",但在 [range]
行范围
搜索 (缺省: 整个文件)。
关于 [/] 和 [!] 见 :search-args 。
[d
[d 显示第一个包含光标所在的关键字的宏定义。搜索从文件头
开始。如果给出一个计数,跳转到第 count 个匹配的行。
]d
]d 类似于 "[d",但是从当前光标位置开始。
:ds :dsearch
:[range]
ds[earch][!] [count]
[/]string[/]
类似于 "[d" 和 "]d",但在 [range]
行范围搜索 (缺省:
整个文件)。
关于 [/] 和 [!] 见 :search-args 。
[D
[D 显示包含光标下的宏的所有的宏定义。找到的每行都显示文件
名和行号。搜索从文件头开始。
]D
]D 类似于 "[D",但是从当前光标位置开始。
:dli :dlist
:[range]
dli[st][!] [/]string[/]
类似于 [D 和 ]D ,但在 [range]
行范围搜索 (缺省: 整
个文件)。
关于 [/] 和 [!] 见 :search-args 。
注意
:dl 功能等同带 "l" 标志位的 :delete ,而不是
:dlist 。
[_CTRL-D
[ CTRL-D
跳转到第一个包含光标所在的关键字的宏定义。搜索从文件头
开始。如果给出一个计数,跳转到第 count 个匹配的行。
]_CTRL-D
] CTRL-D
类似于 "[ CTRL-D
",但是从当前光标开始。
:dj :djump
:[range]
dj[ump][!] [count]
[/]string[/]
类似于 "[ CTRL-D
" 和 "] CTRL-D
",但是在 [range]
行范
围内搜索 (缺省: 整个文件)。
关于 [/] 和 [!] 见 :search-args 。
CTRL-W
CTRL-D
CTRL-W_CTRL-D CTRL-W_d
CTRL-W
d 打开一个新窗口,把光标放在第一个包含光标所在的关键字的
宏定义行。搜索从文件头开始。如果给出一个计数,跳转到第
count 个匹配的行。
:dsp :dsplit
:[range]
dsp[lit][!] [count]
[/]string[/]
类似于 "CTRL-W
d",但是在 [range]
行范围内查找
(缺省: 整个文件)。
关于 [/] 和 [!] 见 :search-args
:che :chec :check :checkpath
:che[ckpath] 列出所有找不到的头文件。
:che[ckpath]! 列出所有的头文件。
:search-args
以上命令通用的参数:
[!] 如果包含,查找包括识别为注释的匹配。如果不包含,则被识别为注释 (根据
'comments' ) 或者是一个 C 注释 ("//" 之后或者 /* */ 之间) 的行不参加匹
配。注意
如果一行被识别为注释,但是注释在行中间结束,匹配可能丢失。另
外,如果一行是注释,但是没有被识别 (根据 'comments'),还是可能从中找到
匹配。例子:
/* comment
foobar */
还是可以找到 "foobar" 的匹配,因为该行没有被识别为注释 (即使语法高亮能
够识别)。
注意
: 因为宏定义一般看起来不像注释,[!] 对 ":dlist"、":dsearch" 和
":djump" 没有影响。
[/] 模式可以被 '/' 包围。没有 '/' 的话,只有完整单词的匹配,就像使用模式
"\<pattern\>" 那样。只有在第二个 '/' 之后,下一个命令才可以通过 '|' 附
加在后。例如:
:isearch /string/ | echo "the last one"
对于 ":djump"、":dsplit"、":dlist" 和 ":dsearch" 命令,模式是按本义理
解的字符串,而不是搜索模式。
可以给 Vim 提供函数,生成 :tag 、 :tselect 等命令和 CTRL-] 这样的普通模式
标签命令所使用的标签列表。
生成标签列表的函数通过设置 'tagfunc' 选项指定。此函数调用时带三个参数:
pattern 标签搜索时使用的标签标识符或模式。
flags 包含控制函数行为的标志位字符串。
info 包含以下项目的字典:
buf_ffname 可用于优先级的完整文件名。
user_data 如有,之前通过 tagfunc 存在标签栈里的定制数
据字符串。
注意
老式函数里,使用参数名前要加上 "a:" 前缀。
目前可以给标签函数传递多至三个的标志位:
'c' 函数是处理中的普通命令调用的
(助记: 标签函数可用光标附近的上下文 (context) 来更好地生成标签
列表。)
'i' 插入模式中,用户在补全标签 (用 i_CTRL-X_CTRL-] 或
'completeopt' 包含 t 时)。
'r' tagfunc 的首个参数应被解释为 pattern (见 tag-regexp ),就像
这样:
:tag /pat
插入模式下的补全也会如此。
如果不给出此标志位,参数通常按本义理解为完整标签名。
注意
设置 'tagfunc' 时, tag-priority 描述的标签优先级不适用。相反,优先级完
全由函数返回的列表元素的顺序来决定。
E987
函数应返回字典项目的列表。每个字典至少包含以下项,所有值都是字符串:
name 标签名。
filename 标签定义所在的文件名。可以是相对于当前目录的相对路径,
也可以是完整路径。
cmd 用于在文件中定位标签的 Ex 命令。可以是 Ex 搜索模式或是
行号。
注意
格式和 taglist() 类似,这样可以使用后者的输出来生成结果。
下列域是可选的:
kind 标签的类型。
user_data 存于标签栈中的定制数据,可用于区别不同操作间的标签。
如果函数返回 v:null 而不是列表,执行标准的标签查找。
在 'tagfunc' 内不允许改动标签栈。 E986
在 'tagfunc' 内不允许关闭窗口或改变窗口。 E1299
下面是一个用于 'tagfunc' 函数的假想例。它使用 taglist() 的输出来生成结果: 按
文件名的逆序生成标签列表。
function TagFunc(pattern, flags, info)
function CompareFilenames(item1, item2)
let f1 = a:item1['filename']
let f2 = a:item2['filename']
return f1 >=# f2 ?
\ -1 : f1 <=# f2 ? 1 : 0
endfunction
let result = taglist(a:pattern)
call sort(result, "CompareFilenames")
return result
endfunc
set tagfunc=TagFunc
vim:tw=78:ts=8:noet:ft=help:norl: