265

How can I jump to to a function definition using vim? For example with Visual Assist, I can type Alt+g under a function and it opens a context menu listing the files with definitions.

How can I do something like this in vim?

pyrrhic
  • 1,479
  • 2
  • 14
  • 25
Jon Clegg
  • 3,322
  • 3
  • 22
  • 22
  • 2
    gnu global is better than ctags. – Jichao Aug 29 '13 at 09:03
  • 6
    @Jichao, can you give us a little more insight about your experience? With what languages did gnu global work better for you? Is there anything else about the context you preferred it in that me be important? Or perhaps you have used it in many different scenarios and you seem to mostly/always prefer it? What do you like about it better? Thanks. – still_dreaming_1 Dec 18 '14 at 19:39
  • @Jichao I turned your comment into a community wiki answer. I would welcome your changes and input for this answer. – still_dreaming_1 Dec 18 '14 at 20:23

11 Answers11

232

Use ctags. Generate a tags file, and tell vim where it is using the :tags command. Then you can just jump to the function definition using Ctrl-]

There are more tags tricks and tips in this question.

Community
  • 1
  • 1
Paul Tomblin
  • 167,274
  • 56
  • 305
  • 392
  • Will this work for PHP? I forgot to mention that I need it to work with C,C++,php and python. – Jon Clegg Mar 11 '09 at 18:36
  • 2
    php is C-like enough that "Exuberant ctags" should work with it. Don't know if it has a python mode. – Paul Tomblin Mar 11 '09 at 18:38
  • 5
    No experience with Cscope. What is is? – Paul Tomblin Mar 12 '09 at 19:29
  • 10
    The similarity to C has nothing to do with CTags support PHP. It supports PHP as well as Python. Have a look at http://ctags.sourceforge.net/languages.html to see the full support. – data Dec 01 '10 at 17:54
  • @dwayne, with the program `ctags` from ctags.sourceforge.net. – Paul Tomblin Jul 29 '11 at 17:31
  • 4
    it would be great to get a reference to where it is best to learn how to operate those ctags. – john-jones Feb 10 '14 at 09:03
  • if you use Ctrl-] and then Ctrl t -- you will return to previous location – serup Sep 02 '16 at 08:18
  • if C-] is not working, then try to generate tags file: using following command : `ctags -R .` – serup Dec 27 '16 at 11:05
  • remember that when using ctags with vim, then open file from scope where tag file is generated, otherwise ctrl-] will not work – serup Dec 27 '16 at 11:23
  • This works out of the box in Android Studio/IdeaVim. – pdoherty926 Jul 17 '18 at 18:34
  • 1
    This is obsolete. Current solution is to use one of the LSP clients availabe for `vim` and `nvim` as plugins in conjunction with a dedicated standalone language server that analyses your code in real time. There are many LSP servers, e.g. Eclipse.JDT.ls for Java, felixfbecker/php-language-server for PHP and more. – cprn Oct 08 '18 at 09:30
  • Actually it's not the real `jump to definition`. It just jumps to the location where it has the same symbol under the cursor, whereas the real `jump to definition` such as the one in IDE, is go to the definition of function or variable within **current class**, even though other classes have same function or variables. – Lewis Chan Dec 19 '18 at 11:38
  • 1
    @cprn disagree. Tags support is still quite easy; no need to fire up a whole language server. I use tags for all my projects with a custom git hook. – D. Ben Knoble Jul 15 '19 at 15:07
  • I guess it depends on tags generator. Last time I was using a PHP specific fork of `ctags` it didn't support namespaces, does it now? Still, all the servers I worked with (at least those in C) were very fast and easy to communicate with through sockets, all that while rarely using more than few megabytes of RAM. Given the other benefits querying one every few key strokes hardly seems excessive. – cprn Jul 15 '19 at 23:04
  • @LewisChan What you mean is namespace-aware jump-to-definition and yes, that's what intellisense gives you. Try CoC - I have the answer in this thread that describes how to use it. – cprn Oct 30 '20 at 10:46
154

If everything is contained in one file, there's the command gd (as in 'goto definition'), which will take you to the first occurrence in the file of the word under the cursor, which is often the definition.

Scottie T
  • 10,481
  • 9
  • 43
  • 59
  • 1
    what if I don't have the word under the cursor (I'd rather type it)? – Fuad Saud Jan 16 '14 at 17:10
  • @FuadSaud just search for it using `/` – LucasB Mar 05 '14 at 16:16
  • 6
    `/` is almost always not precise, as it's going to match all ocurrences. I found out you can actually do `:tag ` to jump to the definition via ctags. – Fuad Saud Mar 05 '14 at 20:00
  • 1
    @Faud Jump To Definition feature relies on pointing an identifier with a cursor (in every IDE). Typing/searching is another feature, you're confusing them. – bloody Apr 05 '20 at 22:07
  • 1
    Beautiful. And it even traverses files within IdeaVIM (free plugin for IntelliJ tools, such as CLion). – Brent Faust Aug 19 '20 at 21:37
110

g* does a decent job without ctags being set up.

That is, type g,* (or just * - see below) to search for the word under the cursor (in this case, the function name). Then press n to go to the next (or Shift-n for previous) occurrence.

It doesn't jump directly to the definition, given that this command just searches for the word under the cursor, but if you don't want to deal with setting up ctags at the moment, you can at least save yourself from having to re-type the function name to search for its definition.

--Edit-- Although I've been using g* for a long time, I've recently discovered two shortcuts for these shortcuts!

(a) * will jump to the next occurrence of the word under the cursor. (No need to type the g, the 'goto' command in vi).

(b) # goes to the previous occurrence, in similar fashion.

N and n still work, but '#' is often very useful to start the search initially in the reverse direction, for example, when looking for the declaration of a variable under the cursor.

Brent Faust
  • 8,214
  • 4
  • 47
  • 52
  • 12
    The difference between `*` and `g*` is word boundaries on the search. `*` does a `\` search (same as `\bkeyword\b` in regular regex), while `g*` searches for `keyword` without word boundaries. – Nicolai S Sep 22 '15 at 10:02
  • 1
    if you have a hundred occurrences of a function in a file, `*` is going to take you on average 50 hits before you find the definition. – naught101 Apr 17 '19 at 22:08
  • 2
    @naught101, but if you have two occurrences of the function, `*` is going to take on average only one hit to find the definition. Unless you do `*` _on_ the definition, at which point you should probably be taking a short break... – jdk1.0 Aug 13 '20 at 17:07
51

Use gd or gD while placing the cursor on any variable in your program.

  1. gd will take you to the local declaration.
  2. gD will take you to the global declaration.

more navigation options can be found in here.

Use cscope for cross referencing large project such as the linux kernel.

0x90
  • 34,073
  • 33
  • 137
  • 218
  • The question is about jumping to the "definition" and not "declaration". If function is declared in a header file e.g. `test.h` g+d will take you to the "declaration". Once there there is no way to jump to the "definition" that is inside "test.c"... Is there any way to do this jump using COC? @cpm answered some things, but did not explain this jump. – 71GA Mar 15 '21 at 18:45
  • I don't know any other way as to use `ctags -R *` in terminal *(inside project folder)* and then inside vim issue command `:tag `. After so many years this is still not implemented... I am so dissapointed... – 71GA Mar 15 '21 at 19:55
32

TL;DR:

Modern way is to use COC for intellisense-like completion and one or more language servers (LS) for jump-to-definition (and way way more). For even more functionality (but it's not needed for jump-to-definition) you can install one or more debuggers and get a full blown IDE experience.

Quick-start:

  1. install vim-plug to manage your VIM plug-ins
  2. add COC and (optionally) Vimspector at the top of ~/.vimrc:
    call plug#begin()
    Plug 'neoclide/coc.nvim', {'branch': 'release'}
    Plug 'puremourning/vimspector'
    call plug#end()
    
    " key mappings example
    nmap <silent> gd <Plug>(coc-definition)
    nmap <silent> gD <Plug>(coc-implementation)
    nmap <silent> gr <Plug>(coc-references)
    " there's way more, see `:help coc-key-mappings@en'
    
  3. call :source $MYVIMRC | PlugInstall to reload VIM config and download plug-ins
  4. restart vim and call :CocInstall coc-marketplace to get easy access to COC extensions
  5. call :CocList marketplace and search for language servers, e.g.:
  • type python to find coc-jedi,
  • type php to find coc-phpls, etc.
  1. (optionally) see install_gadget.py --help for available debuggers, e.g.:
  • ./install_gadget.py --enable-python,
  • ./install_gadget.py --force-enable-php, etc.

Full answer:

Language server (LS) is a separate standalone application (one for each programming language) that runs in the background and analyses your whole project in real time exposing extra capabilities to your editor (any editor, not only vim). You get things like:

  • namespace aware tag completion
  • jump to definition
  • jump to next / previous error
  • find all references to an object
  • find all interface implementations
  • rename across a whole project
  • documentation on hover
  • snippets, code actions, formatting, linting and more...

Communication with language servers takes place via Language Server Protocol (LSP). Both nvim and vim8 (or higher) support LSP through plug-ins, the most popular being Conquer of Completion (COC).

List of actively developed language servers and their capabilities is available on Lang Server website. Not all of those are provided by COC extensions. If you want to use one of those you can either write a COC extension yourself or install LS manually and use the combo of following VIM plug-ins as alternative to COC:

Communication with debuggers takes place via Debug Adapter Protocol (DAP). The most popular DAP plug-in for VIM is Vimspector.

Language Server Protocol (LSP) was created by Microsoft for Visual Studio Code and released as an open source project with a permissive MIT license (standardized by collaboration with Red Hat and Codenvy). Later on Microsoft released Debug Adapter Protocol (DAP) as well. Any language supported by VSCode is supported in VIM.

I personally recommend using COC + language servers provided by COC extensions + ALE for extra linting (but with LSP support disabled to avoid conflicts with COC) + Vimspector + debuggers provided by Vimspector (called "gadgets") + following VIM plug-ins:

call plug#begin()
Plug 'neoclide/coc.nvim'
Plug 'dense-analysis/ale'
Plug 'puremourning/vimspector'
Plug 'scrooloose/nerdtree'
Plug 'scrooloose/nerdcommenter'
Plug 'sheerun/vim-polyglot'
Plug 'yggdroot/indentline'
Plug 'tpope/vim-surround'
Plug 'kana/vim-textobj-user'
  \| Plug 'glts/vim-textobj-comment'
Plug 'janko/vim-test'
Plug 'vim-scripts/vcscommand.vim'
Plug 'mhinz/vim-signify'
call plug#end()

You can google each to see what they do.

Also, pipe character | separates VIM commands put in one line which makes it perfect to set up plug-in dependencies, i.e. vim-textobj-comment doesn't work without vim-textobj-user so if installation of vim-textobj-user fails the rest of the line isn't executed. Here pipe is escaped with backslash \ because it's in a new line but for VIM it's still a one-liner.

cprn
  • 909
  • 1
  • 11
  • 20
  • 1
    coc doesn't seem to offer a way to jump to a function definition by searching though right? i.e. if I know a function name, can I use coc to jump to it from anywhere? – rasen58 Jul 28 '20 at 15:56
  • 2
    Coc supports its own type of extensions and comes with some - among others there's a `symbols list` extension. It's mapped to `s` by default (at least I think it is - if not, just type `:CocList symbols`). When the list triggers you get an input to search for a variable, function, class, interface, whatever. – cprn Aug 03 '20 at 17:20
14

As Paul Tomblin mentioned you have to use ctags. You could also consider using plugins to select appropriate one or to preview the definition of the function under cursor. Without plugins you will have a headache trying to select one of the hundreds overloaded 'doAction' methods as built in ctags support doesn't take in account the context - just a name.

Also you can use cscope and its 'find global symbol' function. But your vim have to be compiled with +cscope support which isn't default one option of build.

If you know that the function is defined in the current file, you can use 'gD' keystrokes in a normal mode to jump to definition of the symbol under cursor.

Here is the most downloaded plugin for navigation
http://www.vim.org/scripts/script.php?script_id=273

Here is one I've written to select context while jump to tag
http://www.vim.org/scripts/script.php?script_id=2507

Mykola Golubyev
  • 52,197
  • 14
  • 81
  • 101
  • Hi @mykola-golubyev , the link your provided in `Detailed description` section of `#2507` script is broken. Can you provide another one please? – FelikZ Mar 03 '14 at 13:14
12

Another common technique is to place the function name in the first column. This allows the definition to be found with a simple search.

int
main(int argc, char *argv[])
{
    ...
}

The above function could then be found with /^main inside the file or with :grep -r '^main' *.c in a directory. As long as code is properly indented the only time the identifier will occur at the beginning of a line is at the function definition.

Of course, if you aren't using ctags from this point on you should be ashamed of yourself! However, I find this coding standard a helpful addition as well.

Judge Maygarden
  • 25,264
  • 8
  • 76
  • 98
  • 15
    I've always wondered why some coders write their signatures that way! – Tarrasch Mar 30 '12 at 08:59
  • Also, when you write your function signatures, including '{' in the first column, you can move around quickly to each function by pressing ]] to go forward in the file and [[ to go backward. – BentChainRing Mar 23 '20 at 12:49
11

1- install exuberant ctags. If you're using osx, this article shows a little trick: http://www.runtime-era.com/2012/05/exuberant-ctags-in-osx-107.html

2- If you only wish to include the ctags for the files in your directory only, run this command in your directory:

ctags -R

This will create a "tags" file for you.

3- If you're using Ruby and wish to include the ctags for your gems (this has been really helpful for me with RubyMotion and local gems that I have developed), do the following:

ctags --exclude=.git --exclude='*.log' -R * `bundle show --paths`

credit: https://coderwall.com/p/lv1qww (Note that I omitted the -e option which generates tags for emacs instead of vim)

4- Add the following line to your ~/.vimrc

set autochdir 
set tags+=./tags;

(Why the semi colon: http://vim.wikia.com/wiki/Single_tags_file_for_a_source_tree )

5- Go to the word you'd like to follow and hit ctrl + ] ; if you'd like to go back, use ctrl+o (source: https://stackoverflow.com/a/53929/226255)

Community
  • 1
  • 1
Abdo
  • 12,299
  • 7
  • 72
  • 94
  • The link to the mentioned Mac article is broken. Here is the updated link: http://runtime-era.blogspot.com/2012/05/exuberant-ctags-in-osx-107.html Your best bet is to install ctags with a tool like Homebrew – ZaydH Dec 02 '18 at 08:35
6

To second Paul's response: yes, ctags (especially exuberant-ctags (http://ctags.sourceforge.net/)) is great. I have also added this to my vimrc, so I can use one tags file for an entire project:

set tags=tags;/
David Wolever
  • 130,273
  • 78
  • 311
  • 472
1

Install cscope. It works very much like ctags but more powerful. To go to definition, instead of Ctrl + ], do Ctrl + \ + g. Of course you may use both concurrently. But with a big project (say Linux kernel), cscope is miles ahead.

hg8
  • 982
  • 1
  • 13
  • 27
0

After generating ctags, you can also use the following in vim:

:tag <f_name>

Above will take you to function definition.

Karun
  • 387
  • 4
  • 14