`
king523103
  • 浏览: 8219 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

VIM: CTags

 
阅读更多

[/home/brimmer/src]$ ctags -R

"-R"表示递归创建,也就包括源代码根目录下的所有子目录下的源程序。"tags"文件中包括这些对象的列表:

l        用#define定义的宏

l        枚举型变量的值

l        函数的定义、原型和声明

l        名字空间(namespace)

l        类型定义(typedefs)

l        变量(包括定义和声明)

l        类(class)、结构(struct)、枚举类型(enum)和联合(union)

l        类、结构和联合中成员变量或函数

VIM用这个"tags"文件来定位上面这些做了标记的对象,下面介绍一下定位这些对象的方法:

1)        用命令行。在运行vim的时候加上"-t"参数,例如:

[/home/brimmer/src]$ vim -t foo_bar

这个命令将打开定义"foo_bar"(变量或函数或其它)的文件,并把光标定位到这一行。

2)        在vim编辑器内用":ta"命令,例如:

:ta foo_bar

3)        最方便的方法是把光标移到变量名或函数名上,然后按下"Ctrl-]"。用"Ctrl-o"退回原来的地方。

注意:运行vim的时候,必须在"tags"文件所在的目录下运行。否则,运行vim的时候还要用":set tags="命令设定"tags"文件的路径,这样vim才能找到"tags"文件。
在函数中移动光标

[{ 转到上一个位于第一列的"{"

}] 转到下一个位于第一列的"{"

{   转到上一个空行

}   转到下一个空行

gd 转到当前光标所指的局部变量的定义

*   转到当前光标所指的单词下一次出现的地方

#   转到当前光标所指的单词上一次出现的地方

Vim 的创造者是一名计算机程序员,因此这就不奇怪 Vim 中有许多帮助编写程序的功能:
跳转到标识符被定义和使用的地方;在另一个窗口中预览有关的声明等等。在下一章中还
会介绍更多的功能。

|29.1| 使用标签
|29.2| 预览窗口
|29.3| 在代码间移动
|29.4| 查找全局标识符
|29.5| 查找局部标识符

     下一章:|usr_30.txt| 编辑程序
     前一章:|usr_28.txt| 折叠
       目录:|usr_toc.txt|

*29.1* 使用标签

什么是标签?标签就是一个标识符被定义的地方。一个例子就是 C 或者 C++ 程序中的函
数定义。标签列表可以保存在一个标签文件中。Vim 可以通过它来从任何地方跳转到该标签,
也就是一个标识符被定义的地方。
   在当前目录下为所有的 C 文件生成标签文件,使用下面的这个命令:

        ctags *.c

"ctags" 是一个独立的程序。大多数 Unix 系统上都已经安装了它。如果你还没有安装,
可以在这里找到 "Exuberant ctags":

        http://ctags.sf.net 

现在你可以使用下面的命令跳转到一个函数定义的地方:

        :tag startlist

这个命令会找到函数 "startlist",即使该函数是在另一个文件中。
   CTRL-] 命令会跳转到当前光标下单词的标签。这样浏览毫无头绪的 C 代码会变得更容
些易。举个例子,假设你在函数 "write_block" 中。你可以看到它调用了函数
"write_line"。但 "write_line" 做了什么呢?将光标置于调用 "write_line" 的地方然
后按 CTRL-],你就跳转到了这个函数的定义的地方了。
   "write_line" 函数调用了 "write_char"。你需要知道它做了什么。将光标定位到调
用 "write_char" 的地方然后按 CTRL-],你就到了定义"write_char" 的地方。

        +-------------------------------------+
        |void write_block(char **s; int cnt) |
        |{                                    |
        |   int i;                            |
        |   for (i = 0; i < cnt; ++i)         |
        |      write_line(s[i]);              |
        |}          |                         |
        +-----------|-------------------------+
                    |
             CTRL-] |
                    |    +----------------------------+
                    +--> |void write_line(char *s)    |
                         |{                           |
                         |   while (*s != 0)          |
                         |      write_char(*s++);     |
                         |}       |                   |
                         +--------|-------------------+
                                  |
                           CTRL-] |
                                  |    +------------------------------------+
                                  +--> |void write_char(char c)             |
                                       |{                                   |
                                       |    putchar((int)(unsigned char)c); |
                                       |}                                   |
                                       +------------------------------------+

":tags" 命令显示你经过的标签列表:
        :tags
          # TO tag         FROM line in file/text 
          1 1 write_line          8 write_block.c 
          2 1 write_char          7 write_line.c 
        > 

现在介绍向回跳转。 CTRL-T 命令跳转到上一个标签。在上例中,你会回到 "write_line"
函数调用 "write_char" 的地方。
   这个命令接受一个计数参数,用来表示跳转回去的标签个数。你已经向前跳转,现在
又跳转了回去。现在我们再一次向前跳转。下面的命令跳转到标签列表中最上面的标签:

        :tag

你可以在前面加上要向前跳转的标签个数。比如:":3tag"。 CTRL-T 同样可以加上一个
计数参数。
   通过这些命令,你可以用 CTRL-] 延着调用树向前跳转, 用 CTRL-T 向回跳转,用
":tags" 命令显示当前位置。


分 割 窗 口

":tag" 命令会将当前窗口的文件替换为包含新函数的文件。怎样才能同时查看两个文件
呢?你可以使用 ":split" 命令将窗口分开然后再用 ":tag" 命令。Vim 有个缩写命令可
以做到这些:

        :stag tagname

使用下面的命令可以分割当前窗口并跳转到光标下的标签:

        CTRL-W ]

如果指定了计数参数,新窗口将包含指定的那么多行。


多 个 标 记 文 件

如果在多个目录中都有文件,你可以在每一个目录下创建一个标签文件。Vim 只能跳转到
那个目录下的标签。
   通过设定 'tags' 选项,你可以使用多个相关的标签文件。 比如:

        :set tags=./tags,./../tags,./*/tags

这会使 Vim 找到当前文件所在目录及其父目录和所有子目录下的标签文件。
   这已经是不少的标签文件了,但也许仍不够。比如,当编辑 "~/proj/src" 目录下的
一个文件时,你无法找到 "~/proj/sub/tags" 目录下的标签文件。对这种情况,Vim
提供了一个查找整个目录树下标签文件的方法,比如:

        :set tags=~/proj/**/tags


单 个 标 记 文 件

当 Vim 在多个地方查找标签文件时,你会听到硬盘在格格作响。这样会有点慢。在这种
情况下,你最好将这些时间花在生成一个大的标签文件上。你可以要等一会儿。
   这得借助上面提到的 "Exuberant ctags" 程序。它有一个选项可以搜索整个目录树:

        cd ~/proj
        ctags -R .

这样做的好处是 "Exuberant ctags" 可以识别多种文件类型,它不仅适用于 C 和 C++
程序,还适用于 Eiffel 甚至 Vim 脚本。请参考 ctags 文档进行调整所用参数。
   现在你只需要告诉 Vim 你的标签文件在何处:

        :set tags=~/proj/tags


多 个 匹 配

当一个函数(或类中的方法)被定义多次, ":tags" 命令会跳转到第一处。如果在当前
文件中存在匹配,那它将会被首先使用。
   你现在可以跳转到同一个标签的其它匹配处:

        :tnext

重复执行这个命令可以找到更多的匹配。如果存在很多匹配,你可以选择要跳转到哪一
个:

        :tselect tagname

Vim 会为你展示一个选择列表:

          # pri kind tag               file 
          1 F   f    mch_init          os_amiga.c 
                       mch_init() 
          2 F   f    mch_init          os_mac.c 
                       mch_init() 
          3 F   f    mch_init          os_msdos.c 
                       mch_init(void) 
          4 F   f    mch_init          os_riscos.c 
                       mch_init() 
        Enter nr of choice (<CR> to abort): 

你现在可以输入要跳转到的匹配代号(在第一列)。其它列的信息可以让你知道匹配在何
处被定义。

可以用这些命令在各匹配的标签间移动:

        :tfirst                 到第一个匹配
        :[count]tprevious       向前 [count] 个匹配
        :[count]tnext           向后 [count] 个匹配
        :tlast                  到最后一个匹配

如果没有指定,[count] 省缺为一。


猜 测 标 签 名

命令行补全是避免输入长标签名的好办法。只需输入开始的一部分然后按 <Tab>:

        :tag write_<Tab>

你会得到第一个匹配。如果这不是你想要的,重复输入 <Tab> 直到你找到正确的匹配。
   有时你只知道一个函数名的一部分,或是你有很多以相同字符串开头而结尾不同的标
记。这时你可以告诉 Vim 使用一个模式来查找标签。

   假设你要跳转到一个包含 "block" 的标签。首先输入:

        :tag /block

现在再利用命令行补全功能:输入 <Tab>。Vim 会找到所有包含 "block" 的标签并使用
第一个匹配。
   标签名前面的 "/" 告诉 Vim 这不是一个确定的标签名而是一个模式。你可以利用有
关查找模式的所有特性。举个列子,假设你要选择所有以 "write_" 开头的标签:

        :tselect /^write_

"^" 指定标签以 "write_" 开头,否则在中间含有 "write_" 的标签名也会被找到。类似
地,"___FCKpd___0quot; 指定标签名结尾处的匹配。


标 签 浏 览 器

CTRL-] 可以让你跳转到光标所在标识符的定义处,因此你可以利用标识符的列表来形成
一个目录。这里给出一个例子。
   首先生成一个标识符列表(需要 Exuberant ctags):

        ctags --c-types=f -f functions *.c

现在打开 Vim 并在一个垂直分割窗口中编辑这个文件:

        vim
        :vsplit functions

窗口中包含一个所有函数的列表。其它的东西可以被忽略。用 ":setlocal ts=99" 命令
使其显示得更清晰些。
   在这个窗口中,定义一个 mapping:

        :nnoremap <buffer> <CR> 0ye<C-W>w:tag <C-R>"<CR>

移动光标至要跳转到函数的所在行,输入 <Enter>。Vim 会在另一个窗口中跳转到所选择
的函数定义处。


相 关 杂 项

你可以设定 'ignorecase' 选项来忽略标签名里的大小写。

'tagbsearch' 选项标明标签文件是否经过排序。省缺是假定为标签文件已排序,这样会
使查找更快,但如果文件没有被排序是无法工作的。

'taglength' 选项可用来告诉 Vim 一个标签的有效字符个数。

当你使用 SNiFF+ 程序时,你可以利用 Vim 的有关接口 |sniff| 。SNiFF+ 是一个商业
软件。

Cscope 是一个自由软件。它不仅可以找到一个标识符被声明的地方,还可以找到标识符
被使用的地方。 请参考 |cscope|。

*29.2* 预览窗口

当编辑含有函数调用的代码时,你需要使用正确的调用参数。要获知所要传递的值,你可以
查看这个函数是如何定义的。标签机制对此十分适用。如果定义可在另一个窗口内显示那
就更好了。对此我们可以利用预览窗口。
   打开一个预览窗口来显示函数 "write_char":

        :ptag write_char

Vim 会打开一个窗口,跳转到 "write_char" 标签。然后它会回到原来的位置。这样你可
以继续输入而不必使用 CTRL-W 命令。
   如果函数名出现在文本中,你可以用下面的命令在预览窗口中得到其定义:

        CTRL-W }

有一个脚本可以自动显示光标处的标签定义。请参考 |CursorHold-example| 。

用下面的命令关闭预览窗口:

        :pclose

要在预览窗口中编辑一个指定的文件,用 ":pedit" 。这在编辑头文件时很有用,比如:

        :pedit defs.h

最后, "psearch" 可用来查找当前文件和任何包含文件中的单词并在预览窗口中显示匹
配。这在使用没有标签文件的库函数时十分有用。例如:

        :psearch popen

这会在预览窗口中显示含有 popen() 原型的 "stdio.h" 文件:

        FILE    *popen __P((const char *, const char *)); 

你可以用 'previewheight' 选项指定预览窗口打开时的高度。

*29.3* 在代码间移动

因为程序代码是结构化的,Vim 可以识别其中的有关项目。一些特定的命令可用来完成相
关的移动。
   C 程序中经常包含类似下面的代码:

        #ifdef USE_POPEN 
            fd = popen("ls", "r") 
        #else 
            fd = fopen("tmp", "w") 
        #endif 

有时会更长,也许还有套嵌。将光标置于 "#ifdef" 处按 %。Vim 会跳转到"#else"。继
续按 % 会跳转到 "#endif"。再次按下 % 又回到原来的 "#ifdef"。
   当代码套嵌时,Vim 会找到相匹配的项目。这是检查你是否忘记了一个 "#endif" 的
好办法。
   当你在一个 "#ifdef" - "#endif" 块内的某个位置,你可以用下面的命令回到开始
处:

        [#

如果你的位置不是在 "#if" 或 "#ifdef" 之后, Vim 会鸣音。用下面命令可以跳转到下
一个 "#else" 或 "#endif":

        ]#

这两个命令会跳过它所经过的 "#if" - "#endif" 块。
例如:

        #if defined(HAS_INC_H) 
            a = a + inc(); 
        # ifdef USE_THEME 
            a += 3; 
        # endif 
            set_width(a); 

如果光标在最后一行,"[#" 会移动到第一行。中间的 "#ifdef" - "#endif" 块被跳过。


在 代 码 块 内 移 动

C 代码块包含在 {} 中,有时一个代码会很长。要跳转到外部代码块的开始处,用 "[["
命令。用 "][" 找到结尾处。(前提是 "{" 和 "}" 都在第一列。)
   "[{" 命令跳转到当前代码块的开始处。它会跳过同一级别的 {} 对。"]}" 跳转到结尾。
   一点概述:

                        function(int a)
           +->          {
           |                if (a)
           |       +->      {
        [[ |       |            for (;;)               --+
           |       |      +->   {                        |
           |    [{ |      |         foo(32);             |     --+
           |       |   [{ |         if (bar(a)) --+     | ]}    |
           +--     |      +--           break;     | ]} |       |
                   |            }                <-+     |       | ][
                   +--          foobar(a)                |       |
                            }                          <-+       |
                        }                                      <-+

当编写 C++ 或 Java 代码时,外部代码块是类,而下一级的 {} 是方法。在类内部用
"[m" 可以找到前一个方法的开始。"]m" 会找到下一个方法的开始。

另外,"[]" 向后移动到一个函数的结尾,"]]" 向前移动到一个函数的结尾。函数的结尾
指的是处在第一列的 "}"。

                                int func1(void)
                                {
                                        return 1;
                  +----------> }
                  |
              [] |             int func2(void)
                  |        +-> {
                  |    [[ |            if (flag)
        start     +--      +--                  return flag;
                  |    ][ |            return 2;
                  |        +-> }
              ]] |
                  |             int func3(void)
                  +----------> {
                                        return 3;
                                }

不要忘了你还可以用 "%" 在匹配的 (), {} 和 [] 间移动。这在它们相距很多行时仍然
适用。


在 括 号 内 移 动

"[(" 和 "])" 命令"[}" 和 "]}" 类似,只不过它们适用于 () 对而不是 {} 对。

                                  [(
                   <--------------------------------
                              <-------
                if (a == b && (c == d || (e > f)) && x > y) 
                                  -------------->
                          -------------------------------->
                                       ])

在 注 释 间 移 动

移动到一个注释的开始用 "[/";向前移动到注释的结尾用 "]/"。这只对 /* - */ 注释
有效。

          +->     +-> /*
          |    [/ |    * A comment about      --+
       [/ |       +-- * wonderful life.        | ]/
          |            */                     <-+
          |
          +--          foo = bar * 3;         --+
                                                | ]/
                       /* a short comment */ <-+

*29.4* 查找全局标识符

你在编辑一个 C 程序,想要知道一个变量是被声明为 "int" 还是 "unsigned"。一个快
速的方法是使用 "[I" 命令来查找。
   假设光标在单词 "column" 处。输入:

        [I

Vim 会列出它所找出的匹配行,不仅在当前文件内查找,还会在所有的包含文件中查找。
结果如下所示:

        structs.h 
         1:   29     unsigned     column;    /* column number */ 

相对使用标签文件或预览窗口的好处是包含文件也被搜索。大多数情况下都能找到正确
的声明。即使标签文件已经过期或者你没有为包含文件建立标签也不会影响结果。
   但是一些准备工作是必要的,否则 "[I" 就没法工作。首先,'include' 选项必须指
定文件是如何被包含的。省缺值适用于 C 和 C++。对其它的语言,你需要自己设定。


定 位 包 含 文 件

   Vim 会找到 'path' 选项指定路径中的包含文件。如果缺少某个目录,一些包含文件
将不会被找到。你可以用这个命令来查看:

        :checkpath

它会列出不能找到的包含文件,以及被找到的包含文件。一个输出样例:

        --- Included files not found in path --- 
        <io.h> 
        vim.h --> 
          <functions.h> 
          <clib/exec_protos.h> 

文件 "io.h" 被当前文件包含但无法找到。"vim.h" 可以找到,这样 ":checkpath" 跟进
这个文件并检查其中的包含文件。结果显示无法找到 "vim.h" 包含的 "functions.h" 和
"clib/exec_protos.h" 文件。

        Note:
        Vim 不是一个编译器。它无法识别 "#ifdef" 语句。这就是说所有的
        "#include" 语句都会被使用,即使它在 "#if NEVER" 之后。

给 'path' 选项增加一个目录可以修正无法找到文件的错误。一个好得参考是 Makefile。
注意那些包括 "-I" 的条目,比如 "-I/usr/local/X11"。要增加这个目录,用:

        :set path+=/usr/local/X11

如果有很多的子目录,你可以用 "*" 通配符。例如:

        :set path+=/usr/*/include

这会找到 "/usr/local/include" 以及 "/usr/X11/include" 目录下的文件。

如果你的工程项目的包含文件都在一个套嵌的目录树下,"**" 就非常有用。它会搜索所
有的子目录。例如:

        :set path+=/projects/invent/**/include

这会找到这些目录下的文件:

        /projects/invent/include 
        /projects/invent/main/include 
        /projects/invent/main/os/include 
        etc.

还有其它的可能性。更多信息,请查看 'path' 选项。
   如果你想查看找到的包含文件,用这个命令:

        :checkpath!

你会得到一个(很长)的包含文件列表。为使它更短些,Vim 会对已经找到的文件显示
"(Already listed)" 而不再重新显示一遍。

分享到:
评论

相关推荐

    vim+ctags+cscope

    linux下面vim+ctags+cscope的使用方法,功能非常强大 linux下面vim+ctags+cscope的使用方法,功能非常强大

    vim+ctags+cscope 配置文件

    自己的vim配置文件, 内含: 1. _vimrc 2. plugin: TagList, SuperTab, OmniCppComplete, Code_Complete 3. tags for glibc, C++(stl,stream), Unix98 system, glib-2.0 4. ftplugin for Pro*C/C++

    vim插件ctags安装

    vim插件安装包及安装步骤详解,方便工程源码阅读

    vim+ctags+cscope一键安装(使用)

    vim+ctags+cscope一键安装(使用)

    windows-use-vim-ctags-and-git

    但是有时候又需要使用到windows下面的一些应用,所以开始折腾怎么在windows下使用vim+ctags+git,下面是我整理的记录。 windows使用vim,好多人推荐安装vim工具,但是我用了一下随着windows版本的升级,比如win8,...

    Vim ctags.exe

    vim ctags 函数列表,自动补全

    Vim+ctags用法

    vim+ctags用法,可以很方便的查询你需要的数据类型,结构等信息。

    vim ctags安装和使用

    vim 中Ctags的安装和使用 『插件介绍』 Ctags工具是用来遍历源代码文件生成tags文件,这些tags文件能被编辑器或其它工具用来快速查找定位源代码中的符号(tag/symbol),如变量名,函数名等。比如,tags文件就是...

    vim/ctags/taglist/winmanger黄金组

    vim ctags taglist winmanger安装示例

    用vim+ctags+taglist+cscope打造文本模式下的Kscope

    简单介绍了一下Kscope的用法,希望对大家有所帮助

    vim + ctags + cscope + nerdtree + taglist + vundle

    vim配置文件,包含taglist cscope nerdtree 等配置

    vim+ctags使用

    vim下的配置工具,方便开发者使用,大大提高了代码编写的效率,将你的vim编辑器配置成一个神器!

    vim-tags:Vim的Ctags生成器

    Vim标签Vim-Tags版本0.1.0 Vim的Ctags生成器版权所有(c)2012-2014 Szymon Wrozynski和贡献者关于Ctags支持是Vim的一项重要功能。 一种使用Ctags的方法是Tim Pope的插件方式。 例如,在Rails项目中,当Bundler运行...

    vim+ctags+cscope配置文件V1.0.0

    自己的vim配置文件 1. .vimrc 2. plugins: TagList, SuperTab, OmniCppComplete, Code_Complete DoxygenToolkit, proc 3. glibc, C++(stl,stream), Unix98 system, glib-2.0 的tags文件 4. ftplugin for Pro*C/C++ 5...

    linux-tools:vim73 cscope ctags .vimrc

    linux-tools:vim73 cscope ctags .vimrc

    vim+ctags+cscope配置文件V2.0.6

    自己的vim配置文件 1. .vimrc 2. plugins: TagList, SuperTab, OmniCppComplete, Code_Complete DoxygenToolkit, proc 3. c89, GNU libc, C++(stl,stream), IEEE Std 1003.1-2008, glib-2.0 的tags文件 4. ftplugin ...

    windows cscop+ctags vim各种插件

    windows 环境的ctags和cscope还有DoxygenToolkit.vim minibufexpl.vim Tabular.vim taglist.vim visualmark.vim 插件工具

Global site tag (gtag.js) - Google Analytics