123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- *usr_29.txt* For Vim version 9.0. Last change: 2022 Mar 13
- 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 Universal/Exuberant ctags at:
- http://ctags.io ~
- http://ctags.sf.net ~
- Universal ctags is preferred, Exuberant ctags is no longer being developed.
- 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 Universal or 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 Universal/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 Universal or 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.
- 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:noet:ft=help:norl:
|