In the previous post of this series, I discussed text objects, which allow us to improve the efficiency with which we perform operations on text. In this post, I’ll be discussing how I quickly find the correct file to edit.
I use three methods of navigating files in Vim, depending on how well I know the location of the file I want to open. While some of these methods aren’t built in to Vim, nor are they impossible to replicate in other editors, I have found that these methods integrate into my Vim workflow exceptionally.
:edit command
When I know the location very well, or it is located near the top of my source tree, I will often use Vim’s command line to open the file. This method has the benefit of working just fine on a vanilla Vim install, but it can be greatly improved with a few tips and configuration tweaks.
First, the :e
command opens files relative to the current working directory.
You can check where Vim’s working directory is by running the :pwd
command.
You can optimize the number of keystrokes required to open files by changing
your working directory with :cd
. I usually keep the working directory at the
root of the current project, and move down into a subfolder if
my work is almost entirely contained within. See :help :cd
for more information.
Out of the box, the command line in Vim offers tab completion, however, it can
be vastly improved with the wildmenu
and wildmode
options. These options
enable enhanced capabilities of tab completion on the Vim command line. I
personally prefer using set wildmode=list:longest
, which completes to the
longest common prefix string among the possible choices and displays those partial matches as a
list. There are many other options, and set wildmode=longest:full
is also
common, which behaves similarly but opens the wildmenu
instead of displaying a
list. Or you could combine the approaches by opening the wildmenu
on the
second tab with set wildmode=list:longest,full
. Take a look at the full gamut
of wildmode
option values through :help wildmode
.
Tree Exploration
When dealing with an unfamiliar codebase, I find it very helpful to be able to explore the directory hierarchy and get acquainted with the project structure. Another use case for tree exploration is when pair-programming or explaining a piece of code to someone—the speed of the other methods listed here can be a little disorienting for onlookers.
Vim has an explore view built in, called netrw
and can be accessed by the
:Explore
command. When calling Vim on a directory, it also traditionally opens
the explore view as well. Pressing i
allows you to cycle through different
views, one of which is a tree view. You can set this as the default by putting
let g:netrw_liststyle=3
in your .vimrc
file.
However, There are some issues with netrw
, including producing lots of ‘junk’
buffers and even buffers that have modified
and nomodifiable
set. These can
require you to close vim entirely to get rid of them. From what I gather,
the tree list style is considerably more unstable.
There exist lots of plugins written to augment, replace, or facilitate the use
of netrw
‘s functionality. vim-vinegar is a plugin written by
the prolific and esteemed Tim Pope. The inspiration for the plugin comes from
an extremely insightful vimcast article which discusses how
‘project drawers’ don’t mix well with Vim’s system of splits (like oil and
vinegar). vim-vinegar makes it simple to open an instance of netrw
in the
current buffer, and offers some handy shortcuts like opening a command line
prepopulated with the file under the cursor.
I have used NERDtree for years as my explorer. However, splits are a
huge part of my workflow and because of the points brought up in the oil vs.
vinegar discussion above, I’ve found that this is the method I use the least in
my day to day work. In researching this post I’ve come across Dhruva Sagar’s
port of vim-vinegar which replicates the functionality of tpope’s vinegar
using NERDtree instead of netrw
. Having the explorer open in the same buffer
as opposed to opening in the ‘project drawer’ style might make the explorer a
more natural part of my general work-flow.
Since I do not use most of the heavy-duty features of NERDtree, I’m also planning on investigating alternate explorer implementations like vimfiler and vim-filebeagle to the heavier NERDtree. Another alternative may be to lazy-load the NERDtree plugin so that I only load the plugin when I’m attempting to open the explorer view, as it is infrequent that I open it during any given editing session.
Fuzzy Finding
This is the method I use most of the time when I want to edit another file. In general, it takes only a few keystrokes to uniquely describe a file, no matter how deeply nested it is. The fuzziness of the search allows me to type in as few characters as needed to distinguish the desired file.
I first installed command-t and loved it. After starting my dotfiles repo, I wanted minimal dependencies and replaced command-t with ctrl-p. I prefered the entirely vim-script implementation for portability.
I noticed a performance difference, mainly on large repositories. The time I
spent waiting for the search to complete locked me out of searching, which
often broke my flow. To improve the lookup times I implemented keybindings to
narrow my searches to common directories, like /models
or /lib
. I would
also change my working directory to limit the number of files searched through,
using the same technique I described above. I found that this really made the
tool more ergonomic, but in hindsight I see that I was simply working around
the limitations of the implementation.
I have recently discovered a new fuzzy-finder named fzf that is magnificent. It was written in Go by one of my favourite vimscript developers, Junegunn. The choice of language gives us the ability to compile to a binary, meaning it maintains portability while acheiving a huge speedup on large searching. It isn’t neccessarily a Vim plugin, which is actually a good thing. I can use it from the terminal or I can invoke it through Vim. It comes with fuzzy autocompletion for bash and zsh.
Since fzf is not built specifically for vim, it’s designed to be very flexible
and does not dictate or hold your hand much. You define a ‘source’ that gets a
list of items, and a ‘sink’, a command which accepts an item of that list. For
instance, you might define the source as all the javascript files in the
current project, and the sink could be the :edit
command. Or even more
ambitiously, the source could return a list of synonyms for a word under the
cursor and the sink could replace the word in the buffer with the selected
word.
I found the fzf wiki to be a big help in getting my environment set up
correctly, and it has plenty of examples of how to glue commands together into an
fzf search. I’m currently using this AppleScript to integrate with iTerm2, but
looking forward to getting tmux integrated into my workflow and completing the
text triumvirate. For anyone looking to use fzf with Vim, I recomend checking
out the fzf.vim plugin, also written by Junegunn. It defines a bunch of useful
commands that you are free to call from the Vim command line or create
keybindings of your choosing. Just a few examples are :History
to edit most
recently used buffers, :Tags
to jump to project tags (see ctags), and
:Colors
to change colorschemes.