Exuberant Ctags用法:选择tag文件中所包含的tag类型

网友SamPeng问:

请问哪个参数是不解析方法中变量的。

方法中的变量纯粹是浪费tag标签。从来不用。因为一个文件里有多个同明变量

这个问题比较普遍,因此写一篇文章来解释一下。

大多数人在使用Exuberant Ctags时,一般都使用缺省的ctags -R。一般来讲,这条缺省命令已经可以满足大部分人的需求了。在某些情况下,可能对tag文件中标签的类型有特殊要求,这时就需要进行定制了。

对SamPeng所提出的问题,解决方法如下:

  1. 首先用ctags –list-kinds=<LANG>列出这个语言所支持的标签类型
  2. 然后在生成tag文件时,用ctags –<LANG>-kinds=[+|-]kinds来增加或去掉这种tag类型
  3. 需要把<LANG>换成你所用的编程语言的名字,用ctags –list-languages查看ctags支持哪些语言。

其实我们在文章vim使用进阶: 智能补全中已经用过Exuberant Ctags的定制功能了,在那篇文章里,我们使用命令

ctags -R --c++-kinds=+p --fields=+iaS --extra=+q src 

来为OmniCppComplete插件生成定制的tag文件。仔细分析一下上面这条命令,相信你对Exuberant Ctags的了解会更加深一层的。

从上面的介绍我们可以看到,Exuberant Ctags的功能非常强大(例如,甚至可以用它为任意文件提取tag,你只需要指定生成tag的规则就行了),只是大多数人并不了解。如果你对tag文件的内容有特殊的需求,建议你仔细阅读一下Exuberant Ctags的手册。你可以在这里找到我翻译的Exuberant Ctags中文手册

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/ctags-usage-select-tag-kinds/

文章的脚注信息由WordPress的wp-posturl插件自动生成

vi/vim使用进阶: 使用taglist插件

<< 返回vim使用进阶: 目录

本节所用命令的帮助入口:

:help helptags
:help taglist.txt 

上篇文章介绍了在vim中如何使用tag文件,本文主要介绍如何使用taglist插件(plugin)。

想必用过Source Insight的人都记得这样一个功能:SI能够把当前文件中的宏、全局变量、函数等tag显示在Symbol窗口,用鼠标点上述tag,就跳到该tag定义的位置;可以按字母序、该tag所属的类或scope,以及该tag在文件中出现的位置进行排序;如果切换到另外一个文件,Symbol窗口更新显示这个文件中的tag。

在vim中的taglist插件所实现的就是上述类似的功能,有些功能比SI弱,有些功能比SI更强。而且,taglist插件还在不断完善中!

要使用taglist plugin,必须满足:

  • 打开vim的文件类型自动检测功能:filetype on
  • 系统中装了Exuberant ctags工具,并且taglist plugin能够找到此工具(因为taglist需要调用它来生成tag文件)
  • 你的vim支持system()调用

在文章vimrc初步中,我们使用了vim自带的示例vimrc,这个vimrc中已经打开了文件类型检测功能;在上篇文章中,我们也已用到了Exuberant ctags;system()调用在一般的vim版本都会支持(suse Linux发行版中出于安全考虑,关闭了此功能),所以我们已经满足了这三个条件。

现在我们到http://www.vim.org/scripts/script.php?script_id=273下载最新版本的taglist plugin,目前版本是4.3。

下载后,把该文件在~/.vim/目录中解压缩,这会在你的~/.vim/plugin和~/.vim/doc目录中各放入一个文件:

plugin/taglist.vim – taglist插件
doc/taglist.txt    - taglist帮助文件 

注:windows用户需要把这个插件解压在你的$vim/vimfiles或$HOME/vimfiles目录。

使用下面的命令生成帮助标签(下面的操作在vim中进行):

:helptags ~/.vim/doc 

生成帮助标签后,你就可以用下面的命令查看taglist的帮助了:

:help taglist.txt 

Taglist提供了相当多的功能,我的vimrc中这样配置:

""""""""""""""""""""""""""""""
" Tag list (ctags)
""""""""""""""""""""""""""""""
if MySys() == "windows"                "设定windows系统中ctags程序的位置
let Tlist_Ctags_Cmd = 'ctags'
elseif MySys() == "linux"              "设定linux系统中ctags程序的位置
let Tlist_Ctags_Cmd = '/usr/bin/ctags'
endif
let Tlist_Show_One_File = 1            "不同时显示多个文件的tag,只显示当前文件的
let Tlist_Exit_OnlyWindow = 1          "如果taglist窗口是最后一个窗口,则退出vim
let Tlist_Use_Right_Window = 1         "在右侧窗口中显示taglist窗口 

这样配置后,当你输入”:TlistOpen“时,显示如下窗口:

在屏幕右侧出现的就是taglist窗口,你从中可以看到在main.c文件中定义的所有tag:宏、定义、变量、函数等;你也可以双击某个tag,跳到该tag定义的位置;你还可以把某一类的tag折叠起来(使用了vim的折行功能),方便查看,就像上图中macro和variable那样。更多的功能,请查看taglist的帮助页,本文也会介绍一些常用功能。

下面介绍常用的taglist配置选项,你可以根据自己的习惯进行配置:

  • Tlist_Ctags_Cmd选项用于指定你的Exuberant ctags程序的位置,如果它没在你PATH变量所定义的路径中,需要使用此选项设置一下;
  • 如果你不想同时显示多个文件中的tag,设置Tlist_Show_One_File为1。缺省为显示多个文件中的tag;
  • 设置Tlist_Sort_Type为”name“可以使taglist以tag名字进行排序,缺省是按tag在文件中出现的顺序进行排序。按tag出现的范围(即所属的namespace或class)排序,已经加入taglist的TODO List,但尚未支持;
  • 如果你在想taglist窗口是最后一个窗口时退出vim,设置Tlist_Exit_OnlyWindow为1;
  • 如果你想taglist窗口出现在右侧,设置Tlist_Use_Right_Window为1。缺省显示在左侧。
  • 在gvim中,如果你想显示taglist菜单,设置Tlist_Show_Menu为1。你可以使用Tlist_Max_Submenu_ItemsTlist_Max_Tag_Length来控制菜单条目数和所显示tag名字的长度;
  • 缺省情况下,在双击一个tag时,才会跳到该tag定义的位置,如果你想单击tag就跳转,设置Tlist_Use_SingleClick为1;
  • 如果你想在启动vim后,自动打开taglist窗口,设置Tlist_Auto_Open为1;
  • 如果你希望在选择了tag后自动关闭taglist窗口,设置Tlist_Close_On_Select为1;
  • 当同时显示多个文件中的tag时,设置Tlist_File_Fold_Auto_Close为1,可使taglist只显示当前文件tag,其它文件的tag都被折叠起来。
  • 在使用:TlistToggle打开taglist窗口时,如果希望输入焦点在taglist窗口中,设置Tlist_GainFocus_On_ToggleOpen为1;
  • 如果希望taglist始终解析文件中的tag,不管taglist窗口有没有打开,设置Tlist_Process_File_Always为1;
  • Tlist_WinHeightTlist_WinWidth可以设置taglist窗口的高度和宽度。Tlist_Use_Horiz_Window为1设置taglist窗口横向显示;

在taglist窗口中,可以使用下面的快捷键:

<CR>          跳到光标下tag所定义的位置,用鼠标双击此tag功能也一样
o             在一个新打开的窗口中显示光标下tag
<Space>       显示光标下tag的原型定义
u             更新taglist窗口中的tag
s             更改排序方式,在按名字排序和按出现顺序排序间切换
x             taglist窗口放大和缩小,方便查看较长的tag
+             打开一个折叠,同zo
-             将tag折叠起来,同zc
*             打开所有的折叠,同zR
=             将所有tag折叠起来,同zM
[[            跳到前一个文件
]]            跳到后一个文件
q             关闭taglist窗口
<F1>          显示帮助 

可以用”:TlistOpen“打开taglist窗口,用”:TlistClose“关闭taglist窗口。或者使用”:TlistToggle“在打开和关闭间切换。在我的vimrc中定义了下面的映射,使用<F9>键就可以打开/关闭taglist窗口:

map <silent> <F9> :TlistToggle<cr> 

Taglist插件还提供了很多命令,你甚至可以用这些命令创建一个taglist的会话,然后在下次进入vim时加载此会话。

Taglist插件还可以与winmanager插件协同使用,这将在下篇文章中介绍。

[参考文档]

<< 返回vim使用进阶: 目录

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/advanced-vim-skills-taglist-plugin/

文章的脚注信息由WordPress的wp-posturl插件自动生成

vi/vim使用进阶: 使用标签(tag)文件

<< 返回vim使用进阶: 目录

本节所用命令的帮助入口:

:help 'tags'
:help :tag
:help :tags
:help CTRL-]
:help CTRL-T
:help vimgrep
:help cw
:help pattern 

尽管相关的文章已经很多了,但tag文件实在是太有用了,所以还是啰嗦一次。

Tag文件(标签文件)无疑是开发人员的利器之一,有了tag文件的协助,你可以在vim查看函数调用关系,类、结构、宏等的定义,可以在任意标签中跳转、返回……相信使用过Source Insight的人对这些功能并不陌生,而在vim中,此功能的实现依赖于tag文件。

对于程序来说,Tag文件中保存了诸如函数、类、结构、宏等的名字,它们所处的文件,以及如何通过Ex命令跳转到这些标签。它是一个纯文本文件,因此你可以手工的编辑它,也可以使用脚本对其进行操作。

通常我们使用名为ctags的程序来生成这样的tag文件。vim能直接使用ctags程序所生成的tag文件。在UNIX系统下的ctags功能比较少,所以一般我们使用Exuberant Ctags(在大多数Linux系统上,它是缺省的ctags程序),它能够支持多达33种程序语言,足以满足我们开发的需要了。这里是它的中文手册。如果你的系统上未安装此程序,请到http://ctags.sourceforge.net下载。

emacs则使用etags来生成tag文件,如果希望vim也能支持etags的tag文件格式,需要编译vim时加入”+emacs_tags“选项。在这篇文章介绍了编译vim的方法。

Tag文件需要遵循一定的格式,由Exuberant Ctags生成的tag文件,缺省是如下格式:

{tagname} {TAB} {tagfile} {TAB} {tagaddress} {term} {field} ..  
  • {tagname} – 标识符名字,例如函数名、类名、结构名、宏等。不能包含制表符。
  • {tagfile} – 包含 {tagname} 的文件。它不能包含制表符。
  • {tagaddress} – 可以定位到 {tagname}光标位置的 Ex 命令。通常只包含行号或搜索命令。出于安全的考虑,vim会限制其中某些命令的执行。
  • {term} – 设为 ;” ,这是为了兼容Vi编辑器,使Vi忽略后面的{field}字段。
  • {field} .. – 此字段可选,通常用于表示此{tagname}的类型是函数、类、宏或是其它。

在{tagname}、{tagfile}和{tagaddress}之间,采用制表符(TAB符,即C语言中的”\t”)分隔,也就是说{tagname}、{tagfile}的内容中不能包含制表符。

Tag文件的开头可以包含以”!_TAG_”开头的行,用来在tag文件中加入其它信息。vim能够识别两种这样的标记,经常用到的是”_TAG_FILE_SORTED”标记,例如:

!_TAG_FILE_SORTED<Tab>1<Tab>{anything} 

上面这个标记说明tag文件是经过排序的,并且排序时区分了大小写,对排序的tag,vim会使用二分法来进行查找,大大加快了查找速度;如果值为0,则表示tag文件未经排序;如果值为2,则表示tag文件是忽略大小写排序的。

之所以在这里介绍tag文件的格式,是因为我们在后面提到的lookupfile插件中,会自己生成tag文件。

虽然ctags有为数众多的选项,但通常我们所使用的非常简单。还是以vim 7.0的代码为例,我们执行:

cd ~/src/vim70
ctags –R src 

上面这条命令会在~/src/vim70/目录下生成一个名为tags的文件,这个文件中包含~/src/vim70/src/目录下所有.c、.h文件中的标签。它一个文本文件,你可以用vim打开它看一下。此文件缺省按区分字母大小写排序,所以直接可以被vim使用。

现在我们进入vim,执行下面的命令:

:cd ~/src/vim70	"切换当前目录为~/src/vim70
:set tags=tags	"设置tags选项为当前目录下的tags文件 

现在,我们设置好了tags选项,接下来我们使用它:

:tag VimMain

你会看到vim打开了src/main.c文件,并把光标定位到第167行VimMain上。

我们知道,一般主程序的函数名为main,如果你尝试下面的命令:

:tag main
# pri kind tag               file
1 F   f    main              src/xxd/xxd.c
main(argc, argv)
2 FS  d    main              src/if_python.c
46
Choice number (<Enter> cancels): 

这里并没有src/main.c文件,怎么回事呢?这是因为ctags并不是编译器,它在处理编译预处理指令受到局限,因此并没有生成src/main.c中main()函数的标签。你可以在生成tag文件时给ctags指定参数来解决这个问题。见ctags手册

或者你可以用”:grep“或”:vimgrep“来查找main(这篇文章讲解grep及vimgrep的用法):

:cd ~/src/vim70
:vimgrep /\<main\>/ src/*.c
:cw 

这时下面的quickfix窗口将显示出来,在quickfix窗口中找到我们想跳转的位置(本例中是src/main.c),按回车,就可以跳到对应的位置了。

如果你只记得部分的标签名,那么可以使用”tag“命令的搜索模式,你可以输入一个vim正则表达式来表示你所查找的名字,如:

:tag /\C\<\k\+ain\>
# pri kind tag               file
1 F   f    VimMain           src/main.c
VimMain
2 F   d    bindtextdomain    src/vim.h
483
3 F   d    bindtextdomain    src/vim.h
502
4 F   d    bindtextdomain    src/vim.h
504
5 F   f    main              src/xxd/xxd.c
main(argc, argv)
6 F   d    textdomain        src/vim.h
488
7 F   d    textdomain        src/vim.h
510
8 F   d    textdomain        src/vim.h
512
9 FS  d    bindtextdomain    src/gui_gtk.c
54
10 FS  d    bindtextdomain    src/gui_gtk_x11.c
37
11 FS  f    cmdsrv_main       src/main.c
cmdsrv_main(argc, argv, serverName_arg, serverStr)
12 FS  d    main              src/if_python.c
46
13 FS  d    textdomain        src/gui_gtk.c
51
14 FS  d    textdomain        src/gui_gtk_x11.c
34
Choice number (<Enter> cancels): 

这表示我想查找一个以一个或多个keyword开始的标签,此标签以ain做为结尾,在查找时区分大小写。要读懂这个正则表达式,请”:help pattern“。

vim会保存一个跳转的标签栈,以允许你在跳转到一个标签后,再跳回来,可以使用”:tags“命令查找你处于标签栈的哪个位置。

我们经常用到的tag跳转命令见下(一般只需要知道CTRL-]和CTRL-T就可以了):

:tag {ident}            "跳转到指定的标签
:tags                   "显示标签栈
CTRL-]                  "跳转到当前光标下的标签
CTRL-T                  "跳到标签栈中较早的标签 

如果想了解更多命令,可以”:help 29.1“(强烈建议程序员完整的阅读usr_29.txt和usr_30.txt)。

如果想更深入了解tag命令和相关知识,可以”:help tagsrch“。

我之前写的一篇关于ctags和cscope的文章,参见:Vim + Cscope/Ctags

[参考文档]

<< 返回vim使用进阶: 目录

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/advanced-vim-skills-use-ctags-tag-file/

文章的脚注信息由WordPress的wp-posturl插件自动生成

vi/Vim + Cscope/Ctags

使用vim + cscope/ctags,就可以实现SourceInsight的功能,以后可以不再用盗版SouceInsight读代码了。
按照vim里cscope的参考手册(在vim中执行”:help cscope”命令),把cscope功能加到.vimrc里后(需要你的vim在编译时选择了”–enable-cscope”选项,否则你需要重新编译vim),配置就算完成了。然后用下面的命令生成代码的符号索引文件:

    cscope -Rbkq


这个命令会生成三个文件:cscope.out, cscope.in.out, cscope.po.out。
其中cscope.out是基本的符号索引,后两个文件是使用”-q”选项生成的,可以加快cscope的索引速度。
上面所用到的命令参数,含义如下:

-R: 在生成索引文件时,搜索子目录树中的代码
-b: 只生成索引文件,不进入cscope的界面
-k: 在生成索引文件时,不搜索
/usr/include目录
-q: 生成cscope
.in.out和cscope.po.out文件,加快cscope的索引速度

接下来,就可以在vim里读代码了。
不过在使用过程中,发现无法找到C++的类、函数定义、调用关系。仔细阅读了cscope的手册后发现,原来cscope在产生索引文件时,只搜索类型为C, lex和yacc的文件(后缀名为.c, .h, .l, .y),C++的文件根本没有生成索引。不过按照手册上的说明,cscope支持c++和Java语言的文件。
于是按照cscope手册上提供的方法,先产生一个文件列表,然后让cscope为这个列表中的每个文件都生成索引。
为了方便使用,编写了下面的脚本来更新cscope和ctags的索引文件:

#!/bin/sh

find . -name "*.h" -o -name "*.c"-o -name "*.cc" > cscope.files
cscope -bkq -i cscope.files
ctags -R


这个脚本,首先使用find命令,查找当前目录及子目录中所有后缀名为”.h”, “.c”和”.cc”的文件,并把查找结果重定向到文件cscope.files中。
然后cscope根据cscope.files中的所有文件,生成符号索引文件。
最后一条命令使用ctags命令,生成一个tags文件,在vim中执行”:help tags”命令查询它的用法。它可以和cscope一起使用。

目前只能在unix系列操作系统下使用cscope,虽然也有windows版本的cscope,不过还有很多bug。在Linux技术中坚站上看到有作者在win2000上成功运行了gvim + cscope,详情可以参阅:
  http://www.chinalinuxpub.com/bbs/showthread.php?t=30185
(2009/04/06更新)网友mslk提供了cscope 15.7的win32编译版本下载,下载地址:
http://sourceforge.net/project/showfiles.php?group_id=196604&package_id=232374
感谢他的辛勤工作,大家有时间去他的MSLK项目看看,这个项目目的是为Linux下的工具提供预编译的windows版本。

在vim的网站上,也有人在cygwin中成功运行了vim + cscope,详情请参阅:
  http://vim.sourceforge.net/tips/tip.php?tip_id=338
另外,还有人在windows上安装了XFree86包,然后在Xwindow中运行gvim + cscope。这同样可以在上面的网页中看到。

cscope的主页在:http://cscope.sourceforge.net/

在vim的网站上,有很多和cscope相关的插件,可以去找一下你有没有所感兴趣的。搜索结果在这里: 点这里

另外,我的vim使用进阶系列文章介绍了vim的更多特性。

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/vim-cscope-ctags/

文章的脚注信息由WordPress的wp-posturl插件自动生成

Exuberant Ctags中文手册

[译序]

(Easwy) First of all, I would like to thank the author of Exuberate Ctags, Darren Hiebert,
without his help, I cannot finish the work.

翻译这个手册的想法,最初源于我在写“使用VIM开发软件项目”系列文章(现在改名为”vim使用进阶“时。当时看到大家在使用 ctags 时,
基本都是用 "ctags -R"。其实 ctags 所拥有的能力并不止这些。它的众多选项可以让你方便的控制标签文件的
内容,甚至你可以自己定义一种语言,由 ctags 为它生成标签文件 (这方面的例子,可见下面的链接:
http://ctags.sourceforge.net/EXTENDING.html)

你可以在我的BLOG上找到最新版本的译文: http://easwy.com/blog/
译文可自由使用,转载请保留译序部分。
======

NAME
ctags – 为源代码产生标签文件

SYNOPSIS
ctags [options] [file(s)]

etags [options] [file(s)]

DESCRIPTION
ctags 和 etags 程序 (下文中统称为 ctags,除非特别指明) 为文件中的各种语言对象生成一个索引
(或称为标签) 文件。标签文件允许这些项目能够被一个文本编辑器或其它工具简捷迅速的定位。一个
“标签”是指一个语言对象,它对应着一个有效的索引项 (或者换言之,这个索引项为这个对象而创建)。

可选的,ctags 能够为多种程序语言文件的语言对象信息生成可读格式的交叉索引列表。

标签索引文件被多种编辑器支持。这些编辑器允许用户通过出现在源文件中的名字定位对象,并且跳转到
定义这个名字的文件和行。在这个版本发布时,我们所知的编辑器包括:

Vi(1)及其变种(例如,Elvis, Vim, Vile, Lemmy), CRiSP, Emacs, FTE (Folding Text Editor),
JED, jEdit, Mined, NEdit (Nirvana Edit), TSE (The SemWare Editor), UltraEdit, WorkSpace,
X2, Zeus

Ctags可以为许多种不同的程序语言产生不同类型的标签。要获得完整的程序语言支持列表、它们被识别
的名字、为它们所产生的标签的的类型,请见 –list-languages 和 –list-kinds 选项。

SOURCE FILES
除非定义了 –language-force 选项,每个源文件的语言类型将根据文件名到程序语言名的映射自动选择。
每种程序语言的映射可以通过 –list-maps 选项查看,并且可以通过 –langmap 选项修改。在支持的平
台上,如果文件的名字没有映射到一种程序语言并且这个文件是可执行的,将检查文件的第一行,看该文
件是不是一种可识别编程语言的 "#!" 脚本。
缺省的,所有其它文件都被忽略。这允许在一个目录的所有文件上执行 ctags (例如,"ctags *" ),或
在整个源代码目录树的所有文件上执行 ctags (例如,"ctags -R")。因为只有那些文件名被映射到一种
程序语言的文件才会被扫描。

[ .h 扩展名的文件被映射为 C++ 文件而不是 C 文件的原因是 .h 扩展名也应用于 C++ 语言,并且把它
当做 C++ 文件对待并没有害处]

OPTIONS
尽管拥有大量的选项,ctags 设置了缺省值 (适合多数情况),因此通常不带任何选项来执行 ctags (例
如,ctags *,或ctags -R),这将为当前目录下所有可识别的源文件生成一个标签文件。下面提供的选项
仅仅为了在有特殊需要时允许用户自定义。

需注意,用来分隔单字母选项和它们参数的空格是可选的。

同样需注意,长格式选项的布尔型参数 (那些以 "–" 开头并且带 "[=yes|no]" 参数的选项) 可以被省
略,在这种情况下隐含为 "=yes" ,而 "=0" 和 "=off" 被认为是 "=no" 。

某些选项在以 etags 模式运行时或被忽略,或会起作用 (见 -e 选项)。这样的选项会特殊注明。

绝大多数选项可以出现在命令行的任意位置,只影响在该选项后面的文件。然而,少数选项必须出现在第
一个文件名之前,这样的选项也会特殊注明。
带程序语言名字的选项允许名字是大写或小写。见 –list-languages 选项,以获得内建程序语言名的完
整列表。

-a 等同于 –append

-B 使用向上查找的模式 (例如 ?pattern?)。 [在 etags 模式中忽略]

-e 使能 etags 模式,这将创建 Emacs 编辑器使用的标签文件。可选的,如果包含 "etags" 调用
ctags 时 (通过重命名,或者创建符号链接到可执行文件的方式),会使能 etags 模式。这个选项
必须出现在第一个文件名之前。

-f tagfile
使用所指定的 tagfile 做为标签文件的名字 (缺省是 "tags",或 "TAGS" 当以etags模式运行时)。
如果 tagfile 被定义成 "-",那么标签文件被输出到标准输出。如果 tagfile 存在并且它的第一
行不是有效的标签行时,ctags 将拒绝执行。如果你错误的输入了 "ctags -f *.c",这会救你一命,
不然它会把其它文件所产生的标签覆盖到你的第一个 C 文件! ctags 也会拒绝接受以一个 "-" (减
号)开头的文件名,因为这很可能是你忘记输入标签文件的名字,而本选项试图把它后面的选项做为
文件名。如果你真的想把你的输出标签文件名命名为 "-ugly",把它定义成 "./-ugly"。这个选项
必须出现在第一个文件名之前。如果这个选项出现多次,只有最后一个生效。

-F 使用向下查找的模式 (例如 /pattern/) (缺省)。 [在 etags 模式中忽略]

-h list
定义一个文件扩展名列表,以句号分隔,这些文件将做为包含文件(或头文件)被解析。要指定没有
扩展名的文件,用一个句号,后面不跟句号以外的字符 (例如,".","..x",".x.")。这个选项只
影响如何解析一种特定类型的标签的作用域 (也就是说,这些标签是全局可见,还是这些标签只在
定义它们的文件中可见);它并不把这些扩展名映射到任何特定的程序语言。任何位于非头文件中的
标签,如果不能被另外一个文件可见 (例如,链接到另外一个文件),那么它的作用域被认为局限于
该文件 (例如,static)。在头文件中的所有类型的标签,它的作用域都不会被认为局限于该文件。
如果列表中的第一个字符是加号,那么该列表中的扩展名将被加到现有列表之后;否则,该列表将
替换现有列表。另外,参见 –file-scope 选项。缺省的列表是 ".h.H.hh.hpp.hxx.h++.inc.def"。
要恢复缺省列表,使用 -h default。注意,如果此选项指定的一个扩展名还没有被映射到一种特定
的程序语言 (见上面的 SOURCE FILES),你也需要使用 –langmap 或 –language-force 选项。

-I identifier-list
定义一个标识符列表,在解析 C 和 C++ 源文件时会对这些标识符进行特殊的处理。这个选项主要
用来处理由于编译预处理宏的使用而引发的特殊情况。当列出的标识符是简单的标识符时,这些标
识符在解析源文件时会被忽略。如果一个标识符以 "+" 字符做为结尾,ctags 将忽略源文件中紧跟
在此标识符后的被括号括起来的参数列表。如果两个标识符以 "=" 字符分隔,在解析时,第一个标
识符将被第二个标识符所替代。标识符列表可以直接在命令行上提供,也可以从一个单独的文件中
读出。如果 identifier-list 的第一个字符是 "@",".",或目录分隔符 ("/" 或 ""), 或前两个
字符是驱动器的盘符 (例如,"C:"),identifier-list 参数将被解释为一个文件名,从这个文件中
读取标识符列表,每行一个标识符。否则,identifier-list 是需要被特殊处理的标识符的列表
(或一组标识符对的列表),每一个标识符被逗号或空格分开,(如果以空格分隔,需要用引号把整个
列表括起来,以使整个列表做为一个命令行参数)。可以使用多个 -I 选项。要清除已定义的标识符
列表,以 "-" 做为 identifier-list 参数。

这个特性在编译预处理宏的出现会导致句法混淆的时候非常有用。实际上,这是解决源文件中干扰
语法的宏所引发的问题的最好办法 (见下面的 CAVEATS)。下面的例子详细描述这点。

int foo ARGDECL4(void *, ptr, long int, nbytes)

在上面的例子中,宏 "ARGDECL4" 将被错误的解释为函数的名字,而不是正确的名字 "foo"。定义
-I ARGDECL4 会获得正确的结果。

/* creates an RCS version string in module */
MODULE_VERSION("$Revision: 1.41 $")

在上面的例子,宏定义看起来非常像一个函数的定义,因为它没有以分号结尾 (实际上,它后面甚
至还可以跟一个全局变量定义,这样看起来更像一个 K&R 风格的函数参数定义)。实际上,在试图
完成这个看起来像函数的定义时,可能会导致文件的其它部分被跳过。定义 -I MODULE_VERSION+
可以避免这样的问题。

CLASS Example {
// your content here
};

上面的例子使用了 "CLASS" 做为预处理宏,它在不同的平台上被扩展为不同的东西。例如,在
Win32 平台上它可能被定义为 "class __declspec(dllexport)",而在 UNIX 上简单的被定义为
"class"。通常,没有 C++ 的 "class" 关键字将导致源文件被错误的解析。定义 -I CLASS=class
能够得到正确的结果。

-L file
在文件 file 中读取需要产生标签文件的文件列表。如果 file 被指定为 "-",那么文件列表由标
准输入上读取。通过这个选项读到的文件将在命令行上给出的文件之后被处理。输入中的选项也会
被接受 (*1)。如果此选项被定义多次,只使用最后一个。注意:file 以行的方式被读取,只以换
行符做为分隔符,空格被认为是有意义的,这是为了支持文件名中包含空格的情况;如果输入中包
含选项,这会影响选项如何被解析 (*2)。

-n 同 –excmd=number。

-N 同 –excmd=pattern。

-o tagfile
同 -f tagfile。

-R 同 –recurse。

-u 同 –sort=no (也就是 "unsorted",不排序)。

-V 同 –verbose。

-w 此选项被悄悄忽略。仅为兼容 SVR4 Unix 的 ctags。

-x 打印一个表格形式的、可读的交叉索引 (xref) 文件到标准输出,而不是产生一个标签文件。输出
的信息包括:标签名字;标签类型;行号,文件名和标签所定义行的内容 (多余的空格被压缩)。不
会写标签文件,并且所有影响标签文件输出的选项都被忽略。这个特性的一个应用实例是为源文件
中定义的函数生成一个列表 (例如,ctags -x –c-kinds=f file),或为源文件中所有外部可见全
局变量生成一个列表 (例如,ctags -x –c-kinds=v –file-scope=no file)。这个选项必须出现
在第一个文件名之前。

–append[=yes|no]
指明为指定文件生成的标签是增加到标签文件已存在内容的后面,还是替换它们。此选项缺省关闭。
这个选项必须出现在第一个文件名之前。

–etags-include=file
在标签文件中包含一个到 file 的引用。此选项可以被指定任意多次。这个选项支持 Emacs 在一个
标签文件中包含另外一个标签文件的功能。[只在 etags 模式中有效]

–exclude=[pattern]
将 pattern 加到排除文件/目录列表中。这个选项可以被指定任意多次。对每一个 ctags 处理的文
件名,都会把该文件的完整路径 (例如,some/path/base.ext) 以及文件名 (例如,base.ext) 与
此选项定义的每个 pattern 进行比较,这允许 pattern 只匹配一个给定的文件名而不管其路径,
或者只匹配一个指定的路径。如果你所用的 C 编译器的运行库支持,那么 pattern 中可以包含
Unix 上通用的 shell 通配符 (不是正则表达式) (确保把这个选项的参数用引号括起来,以保证通
配符在传给 ctags 之前不会被 shell 扩展;另外,要知道通配符可以匹配 "/" 字符)。 你可以通
过检查 –version 选项的输出来确定在你的平台上 shell 通配符是否可用,(如果可用,) 在编译
的特性表中将包含 "+wildcards";否则将通过简单的文本比较来检查 pattern 与文件名的匹配。

如果 pattern 以字符 "@" 开始,那么剩余的字符串将被解释成一个文件的名字,由此文件中读取
排除模式字串,每行一个。如果 pattern 为空,排除列表将被清空。注意,在程序启动时,缺省的
排除列表包含"EIFGEN","SCCS","RCS",和"CVS",这些是在处理 –recurse 选项时不想意外进入
的目录名。

–excmd=type
定义在源文件中定位标签时所用的 EX 命令的类型。[在 etags 模式中忽略]

type 的有效值为 (用整个单词或用第一个字母都可以):

number 在标签文件中只使用行号来定位标签。这有4个优点:
1. 明显减小最终标签文件的大小。
2. 消除因为定义标签的行被修改而导致使用 pattern 查找标签失败的情况,导致模式
匹配失败 (注意,有些编辑器,例如vim, 够在很多这样的情况中恢复)。
3. 消除在查找雷同的匹配时,找到不正确的源码行的情况 (见下面的 BUGS)。
4. 在标签文件中为内容相同的行保留多个不同的表项。在 pattern 模式,重复的表项
被丢弃,因为它们产生的查找字串是相同的,保存重复的表项没有意义。

但是,这个选项有一个显著的缺点:对源文件的更改会导致标签文件中的行号记录不再对
应源文件的行号,导致跳转到某些标签时偏离标签定义位置一行或多行。大体上讲,这个
选项最好用在那些不打算更改的源文件上。选择这个选项导致下面的选项被忽略:-BF。

pattern 对所有标签只使用搜索字串,与行号不同,行号通常用于宏定义。优点是标签文件产生后,
增加或删除行不会引用 到旧的行号。

mixed 在这个模式,除少数例外,通常都使用搜索字串。对 C 语言,行号用于宏定义标签。这
是原始的 ctags 生成的缺省格式,因此,保留这个选项的缺省值。对 Fortran,common
块使用行号,因为它们的源码行通常都相同,使搜索模式在查找所有匹配时没有用处。

–extra=[+|-]flags
指定是否为特定类型的信息增加额外的标签条目。flags 参数是一组单字母标记,每个代表标签文
件中的一种额外的标签条目。如果 flags 前带 "+" 或 "-" 字符,会向当前生效的标记中加入,或
删除这些标记。否则 flags 替代当前的设置。每个标记的含义如下:

f 为每个源文件的文件名包含一个条目 (例如,"example.c"),它定位到文件的第一行。

q 为每个类成员包含一个额外的类修饰符条目 (为那些支持这类信息的编程语言;当前包括
C++, Eiffel 和 Java)。修饰符标签的实际格式取决于定义该标签的语言 (使用这种语言中
修饰符被定义的那种格式)。对 C++来说,格式为 "class::member";对 Eiffel 和 Java,
格式为 "class.member"。当标签文件中一个标签的名字出现多次时,这将更容易的定位到
特定的标签。然而需注意,这有可能使标签文件的大小不止增加一倍。

–fields=[+|-]flags
定义标签文件表项中的有效扩展字段 (见下面的 TAG FILE FORMAT,以获得更多信息)。flags 参数
是一组单个字母标记, 每一个代表一种类型的扩展字段,具有如下含义 (缺省为禁用,除非下面有
注明):

a 类成员的访问控制信息
f 作用域局部于文件 [使能]
i (关于)继承的信息
k 使用一个字符表示的标签类型 [使能]
K 标签类型的完整名称
l 包含该标签的源文件的编程语言类型
m (关于)实现的信息
n 标签出现的行号
s 标签的范围 [使能]
S 函数的指纹 (例如,原型或参数列表)
z 在 kind 字段中包含 "kind:" 关键字
t 把变量或 typedef 的类型和名字做为 "typeref:" 字段 [使能] (*3)

每个字母或字母组合的前面可以为 "+" ,表示将它加到缺省集合,或者为 "-",表示排除它。如果
既没有 "+" 前缀也没有 "-"前缀,只有在 flags 中明确列出的类型被包含在输出中 (也就是说,
覆盖缺省集合)。如果 –format=1 选项定义了,此选项被忽略。此选项缺省值为 "fkst"。

–file-scope[=yes|no]
指明作用域只在一个文件的标签 (即只在定义它们的文件中可见,不能被其它文件见到的标签,例
如 "static" 的标签) 是否被包含在输出中。又见 -h 选项。这个选项缺省使能。

–filter[=yes|no]
使 ctags 表现的像一个过滤器,由标准输入读取文件的名字,并一个文件接一个文件的输出它们的
标签。如果 –sorted 选项使能,只对文件内定义的标签排序。文件由标准输入上按行读入 (见 -L
选项的备注 ),并且这些文件在命令行及 -L 选项指定的文件之后处理。本选项使能时, -f,-o
和 –totals 选项被忽略。这个选项太过高深,缺省为禁用。这个选项必须出现在第一个文件名之前。

–filter-terminator=string
在 –filter 选项使能时,定义一个字符串,在一个文件的标签解析完后,会打印这个字符串到标
准输出。这允许读取 ctags 输出的应用程序能够确定一个文件的输出在什么时候结束。注意,如果
读入文件名是一个目录,并且 –recurse 选项使能,这个字符串只在该目录中的所有标签之后输出
一次。这个字符串总是被文件的最后一个标签的换行符隔开。这个选项太过高深,缺省为空。这个
选项必须出现在第一个文件名之前。

–format=level
改变输出标签文件的格式。当前有效的 level 只有 1 或 2。级别1指定原始的标签文件格式,级别2
指定一种新的扩展格式,里面包含扩展字段 (但使用了一种手段,使之仍后向兼容原始的 vi(1)
现)。缺省的级别为 2。这个选项必须出现在第一个文件名之前。 [在 etags 模式中忽略]

–help
向标准输出打印一个详细用法描述,然后退出。

–if0[=yes|no]
指定是否对于 "#if 0" 编译预处理分支中的非宏标签进行检查 (宏标签总被包含)。因为这种构造
是为了禁用代码,所以此选项的缺省值为 no。注意,这只是指明一种偏好,并不能保证在 "#if 0"
分支中的代码真的被跳过,因为产生标签的算法会在编译预处理条件太复杂时会解析条件编译的每
一个分支。

–<LANG>-kinds=[+|-]kinds
为特定的编程语言指定一个与语言相关的标签种类 (或类型) 的列表,这些内容会被包含在输出文
件中,在这里 <LANG> 不区分大小写,并且是内建语言名的一种 (见 –list-languages 选项以获
得完整列表)。kinds 参数是一组单字母标记,用来指明 (特定于这种语言的) 标签类型是包含在输
出中,还是不包含。这些特定标记集基于每种程序语言被识别,它们的含义以及缺省值可以由
–list-kinds 选项列出。每个字母或组合可以以 "+" 做前缀,表示在缺省值中加入它,或者以 "-"
做前缀,表示在缺省值中排除它。如果不以 "+" 或 "-" 为前缀,只有在 kinds 中明确列出的类型
被包含在输出中 (就是说,覆盖这种编程语言的缺省值)。

做为 C 语言的一个例子,要想在缺省标签类型中加入函数原型和外部变量定义,但是排除宏定义,
使用 –c-kinds=+px-d;要想只包含函数的标签,使用 –c-kinds=f。

–langdef=name
定义一种新的用户自定义语言,name,使用正则表达式进行解析。一旦被定义,name 可以在其它使
用程序语言名字的选项中被使用。这个选项的典型用法是,先定义这种语言,然后使用 –langmap
把文件名映射到它,最后使用 –regex-<LANG> 定义它的标签如何被解析。

–langmap=map[,map[…]]
控制文件名如何被映射到程序语言 (见 –list-maps 选项)。每个以逗号分隔的映射中,包含语言
的名字 (内建语言或用户自定义语言),一个冒号,以及一个文件扩展名和/或文件名模式的列表。
要定义一个文件扩展名,在此扩展名前加上句号 (例如,".c")。要定义一个文件名模式,把这个模
式用括号括起来 (例如,"([Mm]ake-file)")。如果你的 C 编译器的运行库支持,那么文件名模式
中可以包含 Unix 中通用的 shell 通配符 (确保用引号把参数括起来,以保护通配符在传给 ctags
之前不会被 shell 扩展)。 你可以通过检查 –version 选项的输出来确定在你的平台上 shell 通
配符是否可用,(如果可用,) 在编译的特性表中将包含 "+wildcards";否则将通过简单的文本比
较来检查文件名模式与文件名的匹配。要映射一个 (已经使用的) 文件扩展名,首先要取消它与其
它语言的映射关系。

如果映射的第一个字符是一个 "+",那么这个映射中的扩展名和文件名模式将加到这种语言的当前
映射中;否则,这个映射将替换当前映射。例如,为了指定只有扩展名为 .c 和 .x 的文件被当做
C 语言文件,使用 "–langmap=c:.c.x";想同时把扩展名为 .j 的文件加到 Java 语言文件,定义
"–langmap=c:.c.x,java:+.j"。为了把 makefiles (例如,文件名为 "Makefile","makefile",
或具有扩展名 ".mak") 映射到一种称为 "make" 的语言,定义 "–langmap=make:([Mm]akefile).mak"。
想映射没有扩展名的文件,定义一个句号,后面不包含句号以外字符 (例如,".","..x",".x.")。
想要为一种特定的语言清除映射 (这会防止自动为这个语言生成标签),定义一个空的扩展名列表
(例如, "–langmap=fortran:")。想为特定的语言恢复缺省的映射,将映射定义为default。想为
所有的语言恢复缺省的映射,定义 "–langmap=default"。
注意,在判别文件的程序语言时,文件扩展名先于文件名模式被判断。

–language-force=language
缺省的,ctags 自动为一个源文件选择语言,忽略那些不能确定程序语言的文件 (见上面的 SOURCE
FILES)。这个选项强制把每个文件做为指定程序语言 (不区分大小写;内建或用户自定义) 的文件,
而不是根据它们的扩展名自动为其选择语言类型。另外,特殊值 auto 表示语言类型应该被自动选
择 (这否决的本选项的有效方法)。

–languages=[+|-]list
定义一个语言列表,将为这些语言产生标签,list 包含一个逗号分隔的语言名列表 (不区分大小写;
内建或用户自定义)。如果列表的第一个语言前面不是 "+" 或 "-" 字符,在向列表增加或从列表删
除语言前,会先清空当前列表。列表的每个语言都将加入列表,直到遇到一个 "-"。因为 "+" 或
"-" 都可以在列表中出现,在这两个符号后面的语言就相应被加到列表,或从列表中去掉。这样,
使用一个新的列表替换当前列表,或者从当前列表中增加或删除语言都变得很简单。实际会生成标
签的文件列表取决于生效的语言扩展名映射 (见 –langmap 选项)。注意,所有的语言,包括用户
自定义的语言,(缺省)都是使能的,除非使用本选项禁止。列表中的语言名可以是任何内建语言或
一个先前被 –langdef 选项定义的语言。缺省值为 "all",这也是一个可被接受的参数。见
–list-languages 选项以获得一个完整的内建语言名称。

–license
向标准输出打印软件许可证信息,然后退出。

–line-directives[=yes|no]
定义 "#line" 操作符是否应该被识别。它们存在于预处理器的输出中,包括行号,可能还包括生成
这个预处理输出的源文件的名字。当选项使能时,ctags 会生成标签项目,将使用源文件的文件名
和行号,而不是它们在预处理器输出中的位置。标签文件中的实际文件名将和预处理器输出文件具
有同样的路径,这是因为它假设原始文件的位置相对于预处理器输出文件 (当然,除非 #line 操作
符定义的是绝对路径)。这个选项缺省关闭。注意:这个选项通常在和 –excmd-number (-n) 选项
一起使用才比较有用。你也需要使用 –langmap 或 –language-force 选项,如果 ctags 不能识
别预处理器输出文件的扩展名的话。

–links[=yes|no]
指示是否跟踪符号链接 (如果系统支持符号链接的话)。在禁止时,符号链接被忽略。这个选项缺省
打开。

–list-kinds[=language|all]
列出指定语言或全部语言所能够识别的标签种类,然后退出。在标签文件中,每个种类的标签都用
一个单字母的标记来表示,它也用于 –<LANG>-kinds 选项,用以过滤在输出中所包含的标签种类。
注意,有些语言和/或标签种类可能用正则表达式来实现,如果正则表达式支持没有编译到 ctags
中,可能无法支持 (见 –regex-<LANG> 选项)。列出的每个种类都是使能的,除非后面跟有 "[off]"。

–list-maps[=language|all]
列出指定的语言或全部语言的文件扩展名和文件名模式,然后退出。这些扩展名以及文件名模式把
一个文件与特定程序语言相关联。见上面的 –langmap 选项,以及 SOURCE FILES。

–list-languages
列出 ctags 能够识别的程序语言名,然后退出。这些程序语言名称不区分大小写,可以用在
–language-force,–languages,–<LANG>-kinds 和–regex-<LANG> 选项。

–options=file
从 file 中读取附加选项。做为一种特殊情形,如果 –options=NONE 做为命令行的第一个选项,
它将禁止自动从文件或环境变量 (见 FILES) 中读取任何配置选项。

–recurse[=yes|no]
递归进入文件列表中所遇到的目录。如果给出的文件列表为空,并且没有使用 -L 指定文件列表,
那么当前目录被使用 (也就是 ".")。符号链接将被跟踪。如果你不喜欢这样的处理,或者显式的指
定文件列表,或者通过管道将 find(1) 的输出传给 "ctags -L-"。注意,这个选项当前并不能支持
所有的平台。如果 –help 选项的输出中包含本选项,说明它可用。又见 –exclude 选项,以限制
递归行为。

–regex-<LANG>=/regexp/replacement/[kind-spec/][flags]
/regexp/replacement/ 定义一个正则表达式的替换串,与 sed 的 substitution 命令风格类似,
使用它为映射到 <LANG> 语言 (不区分大小写;内建程序语言,或用户自定义程序语言) 的源文件
产生标签。正则表达式 regexp 定义一个扩展正则表达式 (主要为 egrep(1) 所用),它用来定位包
含标签的一个源码行,使用 t 来定义 tab 字符。当一个匹配行被发现,将会生成一个名为
replacement 的标签,replacement 通常会包含特殊的前向引用 1 到 9,以引用 regexp 中的子
表达式。选项参数中的 "/" 分隔字符实际上可以换成任何字符。注意,不管使用哪个分隔符,如果
它在参数中不做分隔用,必须使用 "" 字符对其进行转义。
本选项定义的正则表达式会被添加到这种语言当前的正则表达式列表中,除非省略选项参数,这种
情况当前列表会被清空。
除非由 flags 做出更改,否则 regexp 被作为 Posix 扩展正则表达式解析。对于每个匹配行,
replacement 应该被扩展为一个非空字符串,不然的话会产生一条告警信息。一个可选的标签类型
定义可以跟在 replacement 后面,它用来指定在标签的 "kind" 扩展字段里写入的类型 (见下面的
TAG FILE FORMAT)。kind-spec 的完整格式是一个单个字母,一个逗号,一个名字 (不包含空格),
一个逗号,一个描述,后面跟分隔符,这个格式定义了类型及其文本描述的长、短形式 (使用
–list-kinds 可以显示出来)。类型的名字和/或类型的描述可以被省略。如果 kind-spec 被省略,
它的缺省值为 "r,regex"。最后,flags 是一个或多个单字母字符,对 regexp 的解析有下列影响:

b 此模式被解析为 Posix 的基本正则表达式

e 此模式被解析为 Posix 的扩展正则表达式 (缺省)

i 此模式以忽略大小写的方式被应用

注意,这个选项只在 ctags 编译时加入正则表达式支持时才有效,这取决于你所用的平台。你可通
过检查 –version 选项的输出,以确定编译时是否加入正则表达式支持,(如果支持),输出的编译
特性列表中将包含 "+regex"。

欲获得 ctags 使用的正则表达式的详细信息,见 regex(5,7) 的手册页,或见 regex 的 GUU info
文档 (例如,"info regex")。

–sort[=yes|no|foldcase]
指明标签文件是否按标签名排序 (缺省为排序)。注意,原始的 vi(1) 要求排序标签。foldcase 指
定不区分大小写排序 (或大小写合并排序)。
对大小写合并排序进行快速二叉树查找需要由使用标签文件的工具提供特殊支持,例如 ctags 的
readtags 库,或 Vim 6.2 以上版本 (使用 "set ignorecase")。这个选项必须出现在第一个文件
名之前。[在 etags 模式中忽略]

–tag-relative[=yes|no]
指明标签文件中记录的名字路径应该相对于标签文件所在的目录,而不是相对于当前目录,除非命
令行所指定的文件名使用绝对路径。这个选项必须出现在第一个文件名之前。当运行在 etags 模式
时,缺省为 yes (见 -e 选项),否则缺省值为 no。

–totals[=yes|no]
打印在本次 ctags 运行期间所读入源文件以及所写标签的统计信息。这个选项缺省关闭。这个选项
必须出现在第一个文件名之前。

–verbose[=yes|no]
使能详细模式。打印处理选项的信息,以及在 ctags 处理每个文件时打印一条简洁的消息,描述采
取什么样的动作。通常,ctags 在配置文件中的选项 (见下面的 FILES) 以及 CTAGS 环境变量被读
入前,不会读取命令行参数。然而,如果本选项是命令行的第一个选项,它将在配置文件、CTAGS
环境变量,以及命令行上的每个选项被读入前生效。缺省值为 no。

–version
打印 ctags 的版本信息,然后退出。信息中始终包含字符串 "Exuberant Ctags"。

OPERATIONAL DETAILS
在 ctags 依次处理每个文件时,它试图挨顺序进行以下三步测试来确定文件的程序语言类型:是否文件
的扩展名被映射到一种程序语言,是否文件名匹配一个映射到程序语言的 shell 模式,最后判断是否该
文件可执行并且它的第一行使用 Unix 风格的 "#!" 定义了一个解释器 (如果平台支持的话)。如果程序
语言确定了,这个文件会被打开,接下来相应的语言解析器被调用,以解析当前打开的文件。解析器解析
整个文件,并且在标签文件中为每个语言对象增加一个条目。见下面的 TAG FILE FORMAT,以获得这些条
目的详细信息。

这个 ctags 实现不像旧有的实现那样,对 C 代码的格式有要求。旧的实现往往依赖特殊的预定格式来帮
助它解决编译预处理条件引发的困难。

通常,ctags 试图更巧妙的处理翻译预处理操作符。如果在一条定义了标签的语句中遇到一个编译预处理
条件,ctags 只跟随此条件的第一个分支 (除非第一分支是 "#if 0" ,在这种情况下,只跟随剩下的唯
一一条分支)。这样做的原因是 (如果) 跟随不只一条分支会导致语法不明确,就像下面例子:

#ifdef TWO_ALTERNATIVES
struct {
#else
union {
#endif
short a;
long b;
}

不能同时跟随两个分支,否则括号会不匹配,ctags 将不能识别语法。

由于这些条件很复杂,并且 (分支) 相互排斥,如果这种办法不能正确的解析一个文件,ctags 将重新尝
试另一种不同的方法,这种方法不并选择性的跟随条件预处理分支,而是在 #if 条件分支导致大括号不
匹配时,通过位于第 1 列的大括号 ("}") 来做为一个代码块结束的指示。

Ctags 也尝试对括在两个圆括号中的参数列表进行特殊处理,以接受下面这样的条件结构:

extern void foo __ARGS((int one, char two));

任何紧挨着 "((" 的名字都被自动忽略,而使用在它之前的名字。

C++ 的运算符定义会被特殊处理。为了对所有种类的运算符 (重载或转换) 保持一致,在标签文件中,所
有运算符的名字总是以 "operator " 为前缀 (也就是说,即使实际的运算符定义被写成 "operator<<")。

在创建标签文件,或向标签文件中添加标签后,将根据标签的名字进行排序,删除相同的标签行。

TAG FILE FORMAT
在不以 etags 模式运行时,标签文件中的每个表项占单独的一行,通常每个看起来都如同这样:

tag_name<TAB>file_name<TAB>ex_cmd;"<TAB>extension_fields

字段以及分隔符定义如下:

1. 标签名
2. 单个 tab 字符
3. 文件名,这个标签对应的对象在此文件中定义
4. 单个 tab 字符
5. 在文件中定位此标签的 EX 命令;通常是一个搜索模式 (/pattern/ 或 ?pattern?) 或行号 (见
–excmd)。标签文件格式 2 (见 –format)
在某些情况下扩展了这个 EX 命令,在紧挨着此 EX 命令后面的 EX 命令注释里嵌入了一套扩展
字段 (在下面描述),这样使它仍能向下兼容原始的 vi(1) 实现。

基于内部使用的目的,会向标签文件中写入一些特殊的标签。这些标签的构成使它们始终被排序到文件的
最前面。因此,这些标签的前两个字符被用做标签文件的幻数,以确定正在写入的是一个有效的标签文件,
而不是一个源文件。

注意,记录在标签文件的每个源文件名,和命令行上定义的完全相同。因此,如果你在命令行上指定的是
相对于当前目录的路径的话,它们在标签文件中以同样的方式被记录。然而,见 –tag-relative 选项,
以更改此设置。

如上所说,扩展字段作为注释增加在 EX 命令之后,是以 tab 字符分隔的 "关键字-值" 组合。这些 "关
键字-值" 组合一般为 "key:value" 的格式。它们是否在标签文件中出现,由 –fields 选项控制。可能
的关键字以及它们值的含义见下:

access 指明类成员的可见范围,它的值特定于程序语言。

file 指明此标签只在文件中可见。这个关键字没有相应的值。

kind 指明标签的类型,或种类。它的值要么是上面 –<LANG>-kinds 选项所描述的相应单字母标
志,要么是全名。此字段的关键字部分允许被省略 (实际上,这是缺省设置)。由 –fields
选项控制它的表现。

implementation
如果存在,它指明一个函数或类具有实现的限制 (抽象与具体),它的值特定于程序语言
(对 C++ 而言是 "virtual" 或 "pure virtual";对 Java 而言是 "abstract").

inherits 如果存在,值为一个逗号分隔的类列表,这个类源于列表中的类 (也就是说,它由列表中的
类继承而来)。

signature 如果存在,它的值是函数指纹,表示方法与程序语言相关。完整的函数指纹定义了此函数的
返回类型及它的参数列表格式。这个扩展字段当前只支持基于 C 的程序语言,并且不包括
返回类型。

另外,标签作用域有关的信息也 (在标签文件中) 可用,它的关键字部分是程序语言中的构造名称,它的
值是程序中此构造的名字。作用域表项指明定义此标签的范围。例如,C 语言的结构成员所生成的标签,
会包含一个作用域,看起来像这样 "struct:myStruct"。

HOW TO USE WITH VI
Vi 缺省的期望当前工作目录中有一个名为 "tags" 的标签文件。一旦生成了标签文件,下面的命令执行
按标签索引的特性:

vi -t tag 启动 vi 并且把光标定位在 "tag" 定义所在的文件和行上。

:ta tag 查找一个标签。

Ctrl-] 查找光标下的标签

Ctrl-T 返回跳转到标签前的前一次位置 (不是所有实现都支持)。

HOW TO USE WITH GNU EMACS
Emacs 缺省的期望当前工作目录中有一个名为 "TAGS" 的标签文件。一旦生成了标签文件,下面的命令执
行按标签索引的特性:

M-x visit-tags-table <RET> FILE <RET>
选择所使用的标签文件 "FILE"。

M-. [TAG] <RET>
查找第一个 TAG 定义。缺省的标签是光标下的标识符。

M-* 跳回你先前调用 "M-." 的位置

C-u M-. 查找前一次所查找的标签的下一个定义

阅读 Emacs info 文档的 Tags 主题,以了解更多命令。

HOW TO USE WITH NEDIT
NEdit 的 5.1 及以后版本可以处理新的扩展标签文件格式 (见 –format)。要使 NEdit 使用标签文件,
选择 "File->Load Tags File"。要跳转到一个标签的定义,高亮这个标签,然后按 Ctrl-D。NEdit 5.1
可以从不同的目录读取多个标签文件。设置 X 资源中的 nedit.tagFile 为标签文件的名字,可以使
NEdit 在启动时自动加载这个标签文件。

CAVEATS
由于 ctags 既不是一个预处理器也不是一个编译器,使用预处理宏会使 ctags 漏掉标签或者错误的生成
不正确的标签。虽然 ctags 已经被设计成处理一些的通用情况,但这依旧是提交最多的问题。特别是使
用预处理构造改变 C 的语法结构时,会欺骗 ctags。你可以通过使用 -I 选项避开很多这样的问题。

(*4)
White space is treated as a separator for file names and options read from list files,
specified using the -L option, and in filter mode (specified using the –filter option).
Therefore, it is not currently possible to supply file names or other options contain-ing
embedded white space (spaces, etc.) through these options.

注意,当 ctags 使用模式字串来定位标签时 (见 –excmd 选项),如果另外一个源码行和包含这个标签
的行完全相同,你的编辑器完全有可以跳到错误的行上。下面的例子说明这种情况:

int variable;

/* … */
void foo(variable)
int variable;
{
/* … */
}

取决于你所使用的编辑器,以及你在代码中位置,搜索模式可能会在查找到真正的全局变量定义之前,查
找到 foo() 的局部参数声明,因为这两行完全相同 (因此它们的搜索模式也相同)。这可以通过使用
–excmd=n 来避免。

BUGS
Ctags 具有比 ls(1) 更多的选项.

当解析一个 C++ 成员函数定义时 (例如,"className::function"),ctags 不能确定域分隔符是一个类
名分隔符还是一个 namespace 分隔符,总是把它做一个类名放在扩展字段的作用域部分。另外,如果一
个 C++ 函数定义在类定义外面 (通常都是这样),函数定义中包含的访问限定符 (即 public,protected
或 private) 以及实现信息 (例如 virtual,pure virtual) 在为这个函数生成标签时无法知道。然而,
对于原型,这些信息可用 (例如,–c++-kinds+=p)。

没有为继承自一个类的语言对象产生标签。

ENVIRONMENT VARIABLES
CTAGS 如果这个环境变量存在,在 ctags 启动时会从此环境变量中读取缺省选项,读取发生在下面
FILES 一节中列出的配置文件之后,但在命令行选项之前。命令行中出现的选项会覆盖此环境变
量中的选项。只从这个环境变量中读取选项值。注意,环境变量中的所有空格都被认为是分隔符,
这样传递一个包含空格的选项参数是不可能的。如果这会导致问题,改用配置文件。

ETAGS 与上面的 CTAGS 类似,如果存在,它会在 etags 启动时读取。如果这个环境变量未找到,etags
将尝试改用 CTAGS 环境变量。

TMPDIR 在支持 mkstemp() 的类 Unix 主机上,这个环境变量的值定义了存放临时文件的目录。这在临
时文件太大导致缺省临时文件目录所在的分区无法装下它时比较有用。ctags 只在下列情况时创
建临时文件: (1) 生成一个 emacs 格式的标签文件, (2) 标签文件被输出到标准输出,
(3) 它被编译成使用内部的排序算法来排序标签文件,而不是使用操作系统的 sort 工具。如果
使用系统的 sort 工具,它通常也会使用这个变量。如果 ctags 是 setuid 的,TMPDIR 的值将
被忽略。

FILES
/ctags.cnf (只在 MSDOS,MSWindows)
/etc/ctags.conf
/usr/local/etc/ctags.conf
$HOME/.ctags (在 MSDOS, MSWindows 上是 $HOME/ctags.cnf)
.ctags (在 MSDOS,MSWindows上是 ctags.cnf)
如果这些配置文件中任一个存在,每个都应该包含一个缺省的选项集合,在 ctags 启动时会按列
出的顺序读入这些选项,读入的时刻发生在读取 CTAGS 环境变量以及命令行选项之前。这使得设
置适用于整个系统、每个人或基于项目的缺省选项值成为可能。在编译 ctags 时为它指定一个额
外的配置文件是可能的,它会在上面列出文件被读入之前读取,在 –version 选项输出中的
"custom-conf" 指示这个特性可用。CTAGS 环境变量及命令行中选项会覆盖这些文件中定义的选
项。只从这些文件中读入选项值。注意,选项文件按行读入,行内的空格有效 (因为不能像 shell
那样使用引号)。文件的每行被当做一个命令行参数 (就像它们被单引号括起来一样)。因此,使
用换行符做为命令行参数的分隔标志。

tags ctags 生成的缺省标签文件。

TAGS etags 生成的缺省标签文件。

SEE ALSO
Exuberant Ctags 的官方网站在:

http://ctags.sourceforge.net

参阅 ex(1),vi(1),elvis,或更好的,vim,ctags 的正式编辑器。欲获得 vim 的更多信息,请到
VIM 的 web 网站:

http://www.vim.org/

AUTHOR
Darren Hiebert <dhiebert at users.sourceforge.net>
http://DarrenHiebert.com/

MOTIVATION
"Think ye at all times of rendering some service to every member of the human race."

"All effort and exertion put forth by man from the fullness of his heart is worship, if it
is prompted by the highest motives and the will to do service to humanity."

— From the Baha’i Writings

CREDITS
这个版本的 ctags 最初继承了 Steve Kirkendall <kirkenda@cs.pdx.edu> 的 ctags 并从中获取灵感,
他的 ctags 伴随 Elvis vi 变种发行 (虽然事实上没有使用一行原来的代码)。

荣誉也要归于 Bram Moolenaar <Bram@vim.org>,vim 的作者,他花费如此多的时间和精力开发这个编辑
器 (服务于他人) 以及帮助乌干达的孤儿。

名为 "HOW TO USE WITH GNU EMACS" 的一节是从 GNU etags 的 info 文档中 "偷来" 的。

Darren Hiebert Version 5.6 CTAGS(1)

译者注:

(*1) 原文为 "Options all also accepted in this input" 。经过与作者沟通,本句应为 "Options also
accepted in this input"。意思是“在输入中的选项也会被接受”,也就是说,可以在 file 中加入选项,
这些选项将会应用在其后出现的文件上。这提供了一种非常便捷的方式,允许用户为不同的文件指定不同的
选项。

(*2) 这句话意思是,因为行内的空格被视为有意义的,所以不能再以空格来分隔各个选项,而应该以换行符来分
隔多个选项。

(*3) 按译者的理解,在使用类如 struct,union 这样的复杂数据类型进行类型定义 (typedef) 或直接定义变量
时,会为之增加 "typeref:" 字段。下面两个例子中的代码生成的标签文件就包含此字段:
/* 定义类型 */
typedef struct abc
{
int a;
char b;
} abc;

/* 直接定义变量 */
union {
TEST1,
TEST2
} test;

(*4) 这段话与前面的选项解释相抵触,正在与作者沟通。

[译文版本]
27Apr07, easwy, initial version
28Apr07, easwy, reformat it

原创文章,请阅读页脚的许可方式,转载请注明:转载自易水博客 [ http://easwy.com/blog/ ]

本文链接地址: http://easwy.com/blog/archives/exuberant-ctags-chinese-manual/

文章的脚注信息由WordPress的wp-posturl插件自动生成