Skip to content

Instantly share code, notes, and snippets.

Last active March 25, 2022 07:00
What would you like to do?



Tell Vim to look for tags files:

  • in the directory of the current file,
  • in the working directory,
  • and in every parent directory, recursively,


set tags=./tags;,tags;

See what tags files are found:

:echo tagfiles()

Tell Vim to look for a specific tags file (standard library, reference implementation, etc.) in addition to the standard ones define above:

set tags+=/path/to/somewhere/tags


" after/ftplugin/foo.vim
setlocal tags+=/path/to/somewhere/tags


Jump to the tag under the cursor if there's only one, or list possible targets:


Preview the tag under the cursor if there's only one, or list possible targets:


Jump to the given tag if there's only one, or list possible targets:

:tj[ump] foo

Preview the given tag if there's only one, or list possible targets:

:ptj[ump] bar

Force regex search if you don't want to type the whole name or don't know the exact capitalization:

:tj /foo

Climb up the "tag stack":


And that's about it. See :help tags for more information and write your own mappings if you don't like the default bindings.


Use a super basic timer:

$ while sleep 3; do ctags -R .; done

Or a nicer one:

$ watch -n 3 ctags -R .

Use a file watcher:

$ ag -l | entr ctags -R .
$ ag -l --js path/to/dir | entr ctags -R .
$ ls dist/js/bundle.*.js | entr ctags -R .

Use a file watcher in a loop:

$ ctagsd

Use Git hooks.

Use Vim, manually

:!ctags -R .

Use Vim, automatically:

augroup ctags
    autocmd BufWritePost <pattern> call if executable('ctags') | system('killall ctags && ctags -R . &') | endif
augroup END

Yes, it runs ctags in the background. Yes it's non-blocking. No, it doesn't use the new "async" features. Yes, this has been possible for a very long time. No, one didn't need to be a Vim wizard to come up with that. No, I don't think that's a good idea but it can obviously be done with minimum effort so, there.

Large projects


My Vim-related gists.

Copy link

I've been using this on my config for php files:

  " Regenerate ctags
  " - when tags.lock is older than 2 min, start fresh
  " - regenerate only if tags.lock not exist
  " - when starting job to regenerate, create tags.lock file
  let generate_ctags = 'find . -name tags.lock -mmin +2 -exec rm {} tags \;
        \ && [ ! -f tags.lock ] && touch tags.lock
        \ && ctags -R --languages=php --php-kinds=cfit
        \ && rm -rf tags.lock'
  autocmd BufWritePost *.php :call jobstart(generate_ctags)

Copy link

kutsan commented May 7, 2020

Which approach do you use Romain? I use git hooks as tpope did and it's been going okay.

Copy link

romainl commented May 7, 2020

@kutsan, a combination of the watcher method, with entr, and the manual method. The watcher method for project code, the manual method for library code (node_modules in my case).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment