| *usr_29.txt* For Vim version 7.4. Last change: 2008 Jun 28 |
| |
| VIM USER MANUAL - by Bram Moolenaar |
| |
| Moving through programs |
| |
| |
| The creator of Vim is a computer programmer. It's no surprise that Vim |
| contains many features to aid in writing programs. Jump around to find where |
| identifiers are defined and used. Preview declarations in a separate window. |
| There is more in the next chapter. |
| |
| |29.1| Using tags |
| |29.2| The preview window |
| |29.3| Moving through a program |
| |29.4| Finding global identifiers |
| |29.5| Finding local identifiers |
| |
| Next chapter: |usr_30.txt| Editing programs |
| Previous chapter: |usr_28.txt| Folding |
| Table of contents: |usr_toc.txt| |
| |
| ============================================================================== |
| *29.1* Using tags |
| |
| What is a tag? It is a location where an identifier is defined. An example |
| is a function definition in a C or C++ program. A list of tags is kept in a |
| tags file. This can be used by Vim to directly jump from any place to the |
| tag, the place where an identifier is defined. |
| To generate the tags file for all C files in the current directory, use the |
| following command: > |
| |
| ctags *.c |
| |
| "ctags" is a separate program. Most Unix systems already have it installed. |
| If you do not have it yet, you can find Exuberant ctags here: |
| |
| http://ctags.sf.net ~ |
| |
| Now when you are in Vim and you want to go to a function definition, you can |
| jump to it by using the following command: > |
| |
| :tag startlist |
| |
| This command will find the function "startlist" even if it is in another file. |
| The CTRL-] command jumps to the tag of the word that is under the cursor. |
| This makes it easy to explore a tangle of C code. Suppose, for example, that |
| you are in the function "write_block". You can see that it calls |
| "write_line". But what does "write_line" do? By placing the cursor on the |
| call to "write_line" and pressing CTRL-], you jump to the definition of this |
| function. |
| The "write_line" function calls "write_char". You need to figure out what |
| it does. So you position the cursor over the call to "write_char" and press |
| CTRL-]. Now you are at the definition of "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); | |
| |} | |
| +------------------------------------+ |
| |
| The ":tags" command shows the list of tags that you traversed through: |
| |
| :tags |
| # TO tag FROM line in file/text ~ |
| 1 1 write_line 8 write_block.c ~ |
| 2 1 write_char 7 write_line.c ~ |
| > ~ |
| > |
| Now to go back. The CTRL-T command goes to the preceding tag. In the example |
| above you get back to the "write_line" function, in the call to "write_char". |
| This command takes a count argument that indicates how many tags to jump |
| back. You have gone forward, and now back. Let's go forward again. The |
| following command goes to the tag on top of the list: > |
| |
| :tag |
| |
| You can prefix it with a count and jump forward that many tags. For example: |
| ":3tag". CTRL-T also can be preceded with a count. |
| These commands thus allow you to go down a call tree with CTRL-] and back |
| up again with CTRL-T. Use ":tags" to find out where you are. |
| |
| |
| SPLIT WINDOWS |
| |
| The ":tag" command replaces the file in the current window with the one |
| containing the new function. But suppose you want to see not only the old |
| function but also the new one? You can split the window using the ":split" |
| command followed by the ":tag" command. Vim has a shorthand command that does |
| both: > |
| :stag tagname |
| |
| To split the current window and jump to the tag under the cursor use this |
| command: > |
| |
| CTRL-W ] |
| |
| If a count is specified, the new window will be that many lines high. |
| |
| |
| MORE TAGS FILES |
| |
| When you have files in many directories, you can create a tags file in each of |
| them. Vim will then only be able to jump to tags within that directory. |
| To find more tags files, set the 'tags' option to include all the relevant |
| tags files. Example: > |
| |
| :set tags=./tags,./../tags,./*/tags |
| |
| This finds a tags file in the same directory as the current file, one |
| directory level higher and in all subdirectories. |
| This is quite a number of tags files, but it may still not be enough. For |
| example, when editing a file in "~/proj/src", you will not find the tags file |
| "~/proj/sub/tags". For this situation Vim offers to search a whole directory |
| tree for tags files. Example: > |
| |
| :set tags=~/proj/**/tags |
| |
| |
| ONE TAGS FILE |
| |
| When Vim has to search many places for tags files, you can hear the disk |
| rattling. It may get a bit slow. In that case it's better to spend this |
| time while generating one big tags file. You might do this overnight. |
| This requires the Exuberant ctags program, mentioned above. It offers an |
| argument to search a whole directory tree: > |
| |
| cd ~/proj |
| ctags -R . |
| |
| The nice thing about this is that Exuberant ctags recognizes various file |
| types. Thus this doesn't work just for C and C++ programs, also for Eiffel |
| and even Vim scripts. See the ctags documentation to tune this. |
| Now you only need to tell Vim where your big tags file is: > |
| |
| :set tags=~/proj/tags |
| |
| |
| MULTIPLE MATCHES |
| |
| When a function is defined multiple times (or a method in several classes), |
| the ":tag" command will jump to the first one. If there is a match in the |
| current file, that one is used first. |
| You can now jump to other matches for the same tag with: > |
| |
| :tnext |
| |
| Repeat this to find further matches. If there are many, you can select which |
| one to jump to: > |
| |
| :tselect tagname |
| |
| Vim will present you with a list of choices: |
| |
| # 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): ~ |
| |
| You can now enter the number (in the first column) of the match that you would |
| like to jump to. The information in the other columns give you a good idea of |
| where the match is defined. |
| |
| To move between the matching tags, these commands can be used: |
| |
| :tfirst go to first match |
| :[count]tprevious go to [count] previous match |
| :[count]tnext go to [count] next match |
| :tlast go to last match |
| |
| If [count] is omitted then one is used. |
| |
| |
| GUESSING TAG NAMES |
| |
| Command line completion is a good way to avoid typing a long tag name. Just |
| type the first bit and press <Tab>: > |
| |
| :tag write_<Tab> |
| |
| You will get the first match. If it's not the one you want, press <Tab> until |
| you find the right one. |
| Sometimes you only know part of the name of a function. Or you have many |
| tags that start with the same string, but end differently. Then you can tell |
| Vim to use a pattern to find the tag. |
| Suppose you want to jump to a tag that contains "block". First type |
| this: > |
| |
| :tag /block |
| |
| Now use command line completion: press <Tab>. Vim will find all tags that |
| contain "block" and use the first match. |
| The "/" before a tag name tells Vim that what follows is not a literal tag |
| name, but a pattern. You can use all the items for search patterns here. For |
| example, suppose you want to select a tag that starts with "write_": > |
| |
| :tselect /^write_ |
| |
| The "^" specifies that the tag starts with "write_". Otherwise it would also |
| be found halfway a tag name. Similarly "$" at the end makes sure the pattern |
| matches until the end of a tag. |
| |
| |
| A TAGS BROWSER |
| |
| Since CTRL-] takes you to the definition of the identifier under the cursor, |
| you can use a list of identifier names as a table of contents. Here is an |
| example. |
| First create a list of identifiers (this requires Exuberant ctags): > |
| |
| ctags --c-types=f -f functions *.c |
| |
| Now start Vim without a file, and edit this file in Vim, in a vertically split |
| window: > |
| |
| vim |
| :vsplit functions |
| |
| The window contains a list of all the functions. There is some more stuff, |
| but you can ignore that. Do ":setlocal ts=99" to clean it up a bit. |
| In this window, define a mapping: > |
| |
| :nnoremap <buffer> <CR> 0ye<C-W>w:tag <C-R>"<CR> |
| |
| Move the cursor to the line that contains the function you want to go to. |
| Now press <Enter>. Vim will go to the other window and jump to the selected |
| function. |
| |
| |
| RELATED ITEMS |
| |
| To make case in tag names be ignored, you can set 'ignorecase' while leaving |
| 'tagcase' as "followic", or set 'tagcase' to "ignore". |
| |
| The 'tagbsearch' option tells if the tags file is sorted or not. The default |
| is to assume a sorted tags file, which makes a tags search a lot faster, but |
| doesn't work if the tags file isn't sorted. |
| |
| The 'taglength' option can be used to tell Vim the number of significant |
| characters in a tag. |
| |
| When you use the SNiFF+ program, you can use the Vim interface to it |sniff|. |
| SNiFF+ is a commercial program. |
| |
| Cscope is a free program. It does not only find places where an identifier is |
| declared, but also where it is used. See |cscope|. |
| |
| ============================================================================== |
| *29.2* The preview window |
| |
| When you edit code that contains a function call, you need to use the correct |
| arguments. To know what values to pass you can look at how the function is |
| defined. The tags mechanism works very well for this. Preferably the |
| definition is displayed in another window. For this the preview window can be |
| used. |
| To open a preview window to display the function "write_char": > |
| |
| :ptag write_char |
| |
| Vim will open a window, and jumps to the tag "write_char". Then it takes you |
| back to the original position. Thus you can continue typing without the need |
| to use a CTRL-W command. |
| If the name of a function appears in the text, you can get its definition |
| in the preview window with: > |
| |
| CTRL-W } |
| |
| There is a script that automatically displays the text where the word under |
| the cursor was defined. See |CursorHold-example|. |
| |
| To close the preview window use this command: > |
| |
| :pclose |
| |
| To edit a specific file in the preview window, use ":pedit". This can be |
| useful to edit a header file, for example: > |
| |
| :pedit defs.h |
| |
| Finally, ":psearch" can be used to find a word in the current file and any |
| included files and display the match in the preview window. This is |
| especially useful when using library functions, for which you do not have a |
| tags file. Example: > |
| |
| :psearch popen |
| |
| This will show the "stdio.h" file in the preview window, with the function |
| prototype for popen(): |
| |
| FILE *popen __P((const char *, const char *)); ~ |
| |
| You can specify the height of the preview window, when it is opened, with the |
| 'previewheight' option. |
| |
| ============================================================================== |
| *29.3* Moving through a program |
| |
| Since a program is structured, Vim can recognize items in it. Specific |
| commands can be used to move around. |
| C programs often contain constructs like this: |
| |
| #ifdef USE_POPEN ~ |
| fd = popen("ls", "r") ~ |
| #else ~ |
| fd = fopen("tmp", "w") ~ |
| #endif ~ |
| |
| But then much longer, and possibly nested. Position the cursor on the |
| "#ifdef" and press %. Vim will jump to the "#else". Pressing % again takes |
| you to the "#endif". Another % takes you to the "#ifdef" again. |
| When the construct is nested, Vim will find the matching items. This is a |
| good way to check if you didn't forget an "#endif". |
| When you are somewhere inside a "#if" - "#endif", you can jump to the start |
| of it with: > |
| |
| [# |
| |
| If you are not after a "#if" or "#ifdef" Vim will beep. To jump forward to |
| the next "#else" or "#endif" use: > |
| |
| ]# |
| |
| These two commands skip any "#if" - "#endif" blocks that they encounter. |
| Example: |
| |
| #if defined(HAS_INC_H) ~ |
| a = a + inc(); ~ |
| # ifdef USE_THEME ~ |
| a += 3; ~ |
| # endif ~ |
| set_width(a); ~ |
| |
| With the cursor in the last line, "[#" moves to the first line. The "#ifdef" |
| - "#endif" block in the middle is skipped. |
| |
| |
| MOVING IN CODE BLOCKS |
| |
| In C code blocks are enclosed in {}. These can get pretty long. To move to |
| the start of the outer block use the "[[" command. Use "][" to find the end. |
| This assumes that the "{" and "}" are in the first column. |
| The "[{" command moves to the start of the current block. It skips over |
| pairs of {} at the same level. "]}" jumps to the end. |
| An overview: |
| |
| function(int a) |
| +-> { |
| | if (a) |
| | +-> { |
| [[ | | for (;;) --+ |
| | | +-> { | |
| | [{ | | foo(32); | --+ |
| | | [{ | if (bar(a)) --+ | ]} | |
| +-- | +-- break; | ]} | | |
| | } <-+ | | ][ |
| +-- foobar(a) | | |
| } <-+ | |
| } <-+ |
| |
| When writing C++ or Java, the outer {} block is for the class. The next level |
| of {} is for a method. When somewhere inside a class use "[m" to find the |
| previous start of a method. "]m" finds the next start of a method. |
| |
| Additionally, "[]" moves backward to the end of a function and "]]" moves |
| forward to the start of the next function. The end of a function is defined |
| by a "}" in the first column. |
| |
| int func1(void) |
| { |
| return 1; |
| +----------> } |
| | |
| [] | int func2(void) |
| | +-> { |
| | [[ | if (flag) |
| start +-- +-- return flag; |
| | ][ | return 2; |
| | +-> } |
| ]] | |
| | int func3(void) |
| +----------> { |
| return 3; |
| } |
| |
| Don't forget you can also use "%" to move between matching (), {} and []. |
| That also works when they are many lines apart. |
| |
| |
| MOVING IN BRACES |
| |
| The "[(" and "])" commands work similar to "[{" and "]}", except that they |
| work on () pairs instead of {} pairs. |
| > |
| [( |
| < <-------------------------------- |
| <------- |
| if (a == b && (c == d || (e > f)) && x > y) ~ |
| --------------> |
| --------------------------------> > |
| ]) |
| |
| MOVING IN COMMENTS |
| |
| To move back to the start of a comment use "[/". Move forward to the end of a |
| comment with "]/". This only works for /* - */ comments. |
| |
| +-> +-> /* |
| | [/ | * A comment about --+ |
| [/ | +-- * wonderful life. | ]/ |
| | */ <-+ |
| | |
| +-- foo = bar * 3; --+ |
| | ]/ |
| /* a short comment */ <-+ |
| |
| ============================================================================== |
| *29.4* Finding global identifiers |
| |
| You are editing a C program and wonder if a variable is declared as "int" or |
| "unsigned". A quick way to find this is with the "[I" command. |
| Suppose the cursor is on the word "column". Type: > |
| |
| [I |
| |
| Vim will list the matching lines it can find. Not only in the current file, |
| but also in all included files (and files included in them, etc.). The result |
| looks like this: |
| |
| structs.h ~ |
| 1: 29 unsigned column; /* column number */ ~ |
| |
| The advantage over using tags or the preview window is that included files are |
| searched. In most cases this results in the right declaration to be found. |
| Also when the tags file is out of date. Also when you don't have tags for the |
| included files. |
| However, a few things must be right for "[I" to do its work. First of all, |
| the 'include' option must specify how a file is included. The default value |
| works for C and C++. For other languages you will have to change it. |
| |
| |
| LOCATING INCLUDED FILES |
| |
| Vim will find included files in the places specified with the 'path' |
| option. If a directory is missing, some include files will not be found. You |
| can discover this with this command: > |
| |
| :checkpath |
| |
| It will list the include files that could not be found. Also files included |
| by the files that could be found. An example of the output: |
| |
| --- Included files not found in path --- ~ |
| <io.h> ~ |
| vim.h --> ~ |
| <functions.h> ~ |
| <clib/exec_protos.h> ~ |
| |
| The "io.h" file is included by the current file and can't be found. "vim.h" |
| can be found, thus ":checkpath" goes into this file and checks what it |
| includes. The "functions.h" and "clib/exec_protos.h" files, included by |
| "vim.h" are not found. |
| |
| Note: |
| Vim is not a compiler. It does not recognize "#ifdef" statements. |
| This means every "#include" statement is used, also when it comes |
| after "#if NEVER". |
| |
| To fix the files that could not be found, add a directory to the 'path' |
| option. A good place to find out about this is the Makefile. Look out for |
| lines that contain "-I" items, like "-I/usr/local/X11". To add this directory |
| use: > |
| |
| :set path+=/usr/local/X11 |
| |
| When there are many subdirectories, you can use the "*" wildcard. Example: > |
| |
| :set path+=/usr/*/include |
| |
| This would find files in "/usr/local/include" as well as "/usr/X11/include". |
| |
| When working on a project with a whole nested tree of included files, the "**" |
| items is useful. This will search down in all subdirectories. Example: > |
| |
| :set path+=/projects/invent/**/include |
| |
| This will find files in the directories: |
| |
| /projects/invent/include ~ |
| /projects/invent/main/include ~ |
| /projects/invent/main/os/include ~ |
| etc. |
| |
| There are even more possibilities. Check out the 'path' option for info. |
| If you want to see which included files are actually found, use this |
| command: > |
| |
| :checkpath! |
| |
| You will get a (very long) list of included files, the files they include, and |
| so on. To shorten the list a bit, Vim shows "(Already listed)" for files that |
| were found before and doesn't list the included files in there again. |
| |
| |
| JUMPING TO A MATCH |
| |
| "[I" produces a list with only one line of text. When you want to have a |
| closer look at the first item, you can jump to that line with the command: > |
| |
| [<Tab> |
| |
| You can also use "[ CTRL-I", since CTRL-I is the same as pressing <Tab>. |
| |
| The list that "[I" produces has a number at the start of each line. When you |
| want to jump to another item than the first one, type the number first: > |
| |
| 3[<Tab> |
| |
| Will jump to the third item in the list. Remember that you can use CTRL-O to |
| jump back to where you started from. |
| |
| |
| RELATED COMMANDS |
| |
| [i only lists the first match |
| ]I only lists items below the cursor |
| ]i only lists the first item below the cursor |
| |
| |
| FINDING DEFINED IDENTIFIERS |
| |
| The "[I" command finds any identifier. To find only macros, defined with |
| "#define" use: > |
| |
| [D |
| |
| Again, this searches in included files. The 'define' option specifies what a |
| line looks like that defines the items for "[D". You could change it to make |
| it work with other languages than C or C++. |
| The commands related to "[D" are: |
| |
| [d only lists the first match |
| ]D only lists items below the cursor |
| ]d only lists the first item below the cursor |
| |
| ============================================================================== |
| *29.5* Finding local identifiers |
| |
| The "[I" command searches included files. To search in the current file only, |
| and jump to the first place where the word under the cursor is used: > |
| |
| gD |
| |
| Hint: Goto Definition. This command is very useful to find a variable or |
| function that was declared locally ("static", in C terms). Example (cursor on |
| "counter"): |
| |
| +-> static int counter = 0; |
| | |
| | int get_counter(void) |
| gD | { |
| | ++counter; |
| +-- return counter; |
| } |
| |
| To restrict the search even further, and look only in the current function, |
| use this command: > |
| |
| gd |
| |
| This will go back to the start of the current function and find the first |
| occurrence of the word under the cursor. Actually, it searches backwards to |
| an empty line above a "{" in the first column. From there it searches forward |
| for the identifier. Example (cursor on "idx"): |
| |
| int find_entry(char *name) |
| { |
| +-> int idx; |
| | |
| gd | for (idx = 0; idx < table_len; ++idx) |
| | if (strcmp(table[idx].name, name) == 0) |
| +-- return idx; |
| } |
| |
| ============================================================================== |
| |
| Next chapter: |usr_30.txt| Editing programs |
| |
| Copyright: see |manual-copyright| vim:tw=78:ts=8:ft=help:norl: |