Dumb-jump is a fantastic emacs package for code navigation. It jumps to the definition of a function/class/variable by searching for regular expressions that look like a definition using ag, ripgrep or git-grep/grep. Because it is so simple it works in over 40 languages (including oddities like SQL, LaTeX and Bash) and is easy to extend. While it is slower and less accurate than ctags, for medium sized projects it's fast enough and requiring no setup makes it much more useful in practice. You can even configure a simple .dumbjump file (similar to a .gitignore) to exclude directories to make it faster, or include other directories to jump between packages.

I use it with Evil mode (vim emulation) and bind dump-jump-go to C-]. Unfortunately it doesn't play well with the Evil jump list and when I invoke evil-jump-backward with C-o it jumps back to the wrong place. While I could invoke dumb-jump-back, I like being able to use C-o for a dumb-jump or a search in emacs. This can be done by advising the core jump function in dumb-jump to push the position to evil's jump list. There's probably a prettier way but this does the trick:

;; Preserve jump list in evil
(defun evil-set-jump-args (&rest ns) (evil-set-jump))
(advice-add 'dumb-jump-goto-file-line :before #'evil-set-jump-args)

If you're ever working in Vim proper dim-jump is a substitute for dumb-jump.