Episode #2

Fluent File Navigation

A whirlwind tour of ways to navigate between files in your project. I show how to go to a method/class definition, its invocations ('references'), to any method that matches a regex pattern, or to a tag generated with universal ctags.

April 16, 2020

Show Notes


  • neovim - The vim fork I happen to use. I have no opinion on whether it's better or worse than regular Vim. This video used version 0.4.3
  • universal-ctags - A maintained version of ctags. Used to index ("tag") language objects that can be used in navigation and auto-complete.
  • ripgrep - Faster grep/ack/ag replacement

Vim Plugins

  • fzf.vim - Wrapper around fzf, a command-line fuzzy finder. Responsible for most of my file navigation.
  • vim-lsp - Language Server Protocol integration for Vim. Neovim will soon include a built-in LSP integration, so presumably most of the neovim community will switch away from third party plugins once the feature stabilizes.
  • asyncomplete.vim - The autocomplete ecoystem I used in the video. It's a bit buggy and perhaps others autocomplete engines are better (I haven't compared recently).
  • unimpaired.vim - A bunch of ergonomic "bracket mappings" (e.g. [f to go to previous file)
  • NERDTree - A file tree explorer plugin for vim.



Transcribed by Rugo Obi

An absolutely critical feature for any text editor is the ability to dart between places in the codebase that are important to you. Important files, function definitions... you name it. And then to arrange those files nicely on screen, so you can reference one piece of code when writing another.

In both those respects, Vim has you thoroughly covered.

So I'm going to pull up the fzf file search here and look for analytics.js. I just have to type the first couple of letters there, and it already pops up and I can open it just like that.

Let’s say I also want to search for the ExpenseType in my Ruby land. So this time, I'm going to search by Tags, universal Ctags. And this is basically the symbols, like class names and function names.

So I'm going to find this ExpenseType here and then open it in a vertical split, like so. ctrl-V

And lastly, for good measure, I'm going to open up a third file. And this one's going to be a shell script, so I'm going to specify that it ends in sh$. And then look for the name of it, which is scheduler. I'm going to open that in a horizontal split. ctrl-X

So now I have these three different splits on screen, and I can cycle between them easily. Each of these corresponds to a buffer, so I'm going to type :on to focus on this particular buffer down in that bottom left corner. And you can see it's taking up all the screen real estate. But the other ones aren't gone and I can cycle between them as I need to.

And should I wish to view them all side-by-side again, I can run this command :vert sba, and it'll sort that out. And I can even make one wider, with keyboard shortcuts.

Now, let's close some of these down and start again. I'm going to go back to the analytics.js file, and I'm going to demonstrate some Language Server Protocol features.

So I have this, attachScript function, being imported from library.js.

Let's go with the definition of that. And bingo we've jumped to the library.js file, the definition of attachScript.

Similarly, I might want to go to all the places that this function is being used. Again the Language Server Protocol helps out with that. And you can see at the bottom of the screen, we have all these uses shown and I can cycle between them. Just like so.

Let's next demonstrate another cool feature of Vim: the ability to find the most recently accessed files. Let's say, for example, I don't remember the name of that last JavaScript file I accessed. So I can open up the history search with fzf, and I can scroll up here and I see the library.js one which I recently accessed. So I'm going to pop that open there.

Now, another feature you might want is the ability to search for method names that match a certain pattern, even though you don't know exactly what that method name is. Here you can use something like ripgrep with some regex to sort that out.

So I have some methods in the code with name mark{X}. For example, markAsSeen()

I want to search for that now throughout the codebase, so I'm going to start the regex with a word boundary. The word 'mark' and then an alphanumerical character, at least one of them, and then a function opening parenthesis. :Rg '\bmark\w+\'

And if I do that, you can see it moves me to markOrderState(state) first, and then next to markOrderState, I'm getting all these method definitions here markAsSeen(). Just like that.

The last feature I want to demonstrate is a very very simple one that's going to seem even mundane, but actually it's incredibly useful.

That's the ability to cycle between files in a given folder with a keyboard shortcut.

So for example, I have this made_a_sale.html.erb email In my Ruby on Rails application. Let me open that up here. And you can see if I open up the :NERDTreeCWD on the left, that there are about 14 other similar files in that folder.

Now, let's say I want to confirm that every single one of these files has this ending bit that contains the unsubscribe link and so on.

What I can do is use a keyboard shortcut to cycle alphabetically back and forth, so let me go forwards.

Now I'm in product_now_being_sold_in_another_country.html.erb, which comes later in the alphabet than made_a_sale.html_erb. I can go further again and I can go back and I can use this technique to check that all these files conform to the need I have.