Nvim :help
pages, generated
from source
using the tree-sitter-vimdoc parser.
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 ctags at: https://ctags.io
:tag startlistThis 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); | |} | +------------------------------------+
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::tagYou 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.:stag tagnameTo 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.
:set tags=./tags,./../tags,./*/tagsThis 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
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
:tnextRepeat this to find further matches. If there are many, you can select which one to jump to:
:tselect tagnameVim will present you with a list of choices:
<CR>
to abort):<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 /blockNow 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 in a tag name. Similarly "$" at the end makes sure the pattern matches until the end of a tag.
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 *.cNow start Vim without a file, and edit this file in Vim, in a vertically split window:
vim :vsplit functionsThe 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.:ptag write_charVim 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.
:pcloseTo edit a specific file in the preview window, use ":pedit". This can be useful to edit a header file, for example:
:pedit defs.hFinally, ":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 popenThis 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.#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:
[(
])
/* - */
comments.
+-> +-> /* | [/ | * A comment about --+ [/ | +-- * wonderful life. | ]/ | */ <-+ | +-- foo = bar * 3; --+ | ]/ /* a short comment */ <-+
[IVim 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.
:checkpathIt 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:
:set path+=/usr/local/X11When there are many subdirectories, you can use the "*" wildcard. Example:
:set path+=/usr/*/includeThis would find files in "/usr/local/include" as well as "/usr/X11/include".
:set path+=/projects/invent/**/includeThis will find files in the directories:
: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.
[<Tab>You can also use "[
CTRL-I
", since CTRL-I
is the same as pressing <Tab>
.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.[DAgain, 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:
gDHint: 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; }
gdThis 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; }