Vim for Developers: Part 3— Advanced Vim

David Ondrich
The Startup
Published in
10 min readJul 4, 2020

--

How You’ll Look and Feel After This

Check out the previous posts in this series if you haven’t already!
Vim for Developers: Part 0 — Why Vim?
Vim for Developers: Part 1 — The Basics
Vim for Developers: Part 2 — Advanced Basics

TL;DR — If you’re somewhat familiar with NeoVim/Vim and you’re just looking for a badass config, you can check out my dotfiles here.

Taking It to the Next Level

By now hopefully you’ve read the previous posts and you’re hopping about text files, sans mouse and arrow-keys, with ease.

But what about really using Vim to code? Projects usually have more than one file. How can we really start working with a bunch of different files and directories as efficiently as we do with a standard IDE? I’m glad you asked! Let’s find out.

Words of Encouragement

Before we go on I wanted to say that some of the things you’ll see in this post will be slightly cumbersome. At some point you’ll probably think to yourself “This is not better than an IDE, why bother?” I want to promise you that when we get into plugins, many of these things will get much, much easier. But before that I think it’s important to learn what’s really going on under the hood in Vim, so you have an idea of what your plugins are actually doing. Plus when your PagerDuty goes off in the middle of the night, and you’re SSH-ing into some Linux server, you’ll want to be proficient in plain ‘ole vanilla Vim. You won’t have time to clone your dotfiles.

With that in mind hang in there! Some things will be tough because they’re new. Some things will be tough because they’re tough, but will get better once we get plugins involved. Either way if you stick with it you’ll look back on things you thought were annoying, and think “how did ever I live without that?”

Windows

You’re probably used to working in your IDE with many tabs open. Each tab is a file in the project you’re working in. If you’re anything like I used to be, by lunchtime you have so many tabs open you can’t even see the names of the files anymore. To find the one you’re looking for you’ll probably elect to search for it in the search feature, rather than click through each file.

You’ve also probably noticed that Vim doesn’t have this sort of “tab” feature. So how do you know what files have been opened, or what files are even in your current directory?

Before we get into that we must touch on windows. A window is what you’re actually looking at when you open Vim in your terminal. When you open a new file in Vim you’re looking at a blank window.

A handy move in IDEs is often to split the current file you’re working with in half, so you can look at two different parts of it at the same time. Or, to have two different files open side-by-side. Let’s see how to accomplish that.

Splitting Window, Jumping Between Windows, Closing Window

So what happened in the GIF above. As you can see my cursor is navigating around the Vim tutor file. I split the pane horizontally with the command:

:split

Alternatively, you can split the pane vertically with the command:

:vsplit

Makes sense. Then to hop the cursor between the two windows you use:

ctrl + w (x2)

I then closed the bottom window with the command :q which we covered in previous posts. And yes you can split the splits and so on and so forth to your heart’s desire.

When you have a bunch of splits it may feel be annoying to constantly ctrl + w to keep jumping to the next pane. But have no fear! Just as you can navigate your cursor normally with hjkl you can navigate your cursor jumps!

ctrl + w  + h (or) j (or) k (or) l

The above command will jump in the respective direction of the hjkl you choose.

Finally, you may want to resize your various split windows. The following commands will help you with that:

ctrl + w + +/- :increase/decrease height
ctrl + w + >/< :increase/decrease width
ctrl + w + _ :set height
ctrl + w + | :set width

All the above commands can be multiplied, for example:

10 + ctrl + w + >

will expand the current split 10 columns to the right. And with the set height/width command the number you multiply the command by is the height/width you will set.

Buffers

Now for the good stuff. I bet you’re thinking to yourself “okay I still only know how to work with one file at a time”. That ends now.

If you’re familiar with buffers in the programming sense, that’s exactly what they are in Vim. When you open a file it creates a buffer to that file, and the data is displayed in your window.

If you’re not familiar with buffers, then think about in your current IDE. When you have a bunch of files open, and all their tabs are at the top of your IDE, each one of those would be considered a buffer. But Vim doesn’t have those tabs, it has a different way to manage the buffers (files) that you open.

Let’s walk through a fake-real-life workflow. In GIF form!

In the GIF above I start out by opening Vim without any arguments, so it opens a blank window in my current directory which is vim_examples . Then to check what files are in the directory I use the command:

:E - e for explore perhaps? get creative they're your mnemonics!

As you can see that opens up a menu of sorts that shows any files or directories in your current directory. You might notice there’s a bunch of stuff above the line of ===== ignore it for now (but let me tell you that’s a damn feature-packed menu you’re looking at).

You can move up and down in the menu with your trusty jk keys, and you can even traverse upwards through directories by selecting the .. menu option. To select from the menu you hit enter/return as you may have guessed.

Now you’ve opened a buffer! In this case to a file called text_file_1.txt . What might we do next.

A lot happened in the above GIF so let’s step through it. From my original buffer text_file_1.txt I used the :E command to check out the other files, and I opened up a new buffer text_file_2.txt .

What happened to the buffer for text_file_1.txt ? I switched to a new buffer, but I didn’t explicitly close the original one. And it’s not closed!

:ls - list open buffers

If you’re familiar with *nix terminals this probably looks familiar to you. The trusty :ls command allows us to see a list of open buffers. Unfortunately, you can’t just select a buffer from that list, you’ll notice it prompts you for another command. In this case I go to the next buffer in the list with:

:bn - buffer next

I then go back to the previous buffer with:

:bp - buffer previous

You might have also noticed each buffer has a number next to it. If you have many open buffers it might be annoying to cycle through with :bn and :bp . A useful command is:

:bN

where N in this case refers to the number of the buffer. It will take you right to that buffer!

Let me stress that this is something specifically that will get exponentially easier with plugins.

Windows + Buffers

Continuing with our fake-real-life workflow. Let’s say I want to split my window and work with two buffers at once. Let’s see.

Opening two buffers horizontally

To start out I’m looking at buffer for text_file_1.txt, with the trusty :ls command I see I also want to open text_file_2.txt , to open it and split my window horizontally I used the command:

:sbuffer 3 - split buffer 3(the number of the buffer from menu)

I then hopped my cursor to the original buffer and closed it with :q . It’s important to note this doesn’t actually close the buffer, it closes the split window. If you :ls you will still see that buffer in the list.

How might you split the window vertically?

:vert sb N - vertical split buffer N (buffer number)

N in this case is the number of the buffer from the :ls menu.

Again, I want to stress I know this is cumbersome. Soon enough we’ll see ways to make buffer and pane management much simpler.

Macros

Remember the dot operator from Post 2. You might have noticed that the dot operator only works for repeating the very last thing you did. But what if you want to repeat a few commands together. That’s where macros come in, and let me be the first to tell you, they kick ass.

Macros record a series of commands/movements and allow you to save them to a register. You can save up to 26 macros at any one time. One for each letter of the alphabet.

Macros are super useful for applying the same series of commands on different texts, and they absolutely crush repetitive tasks.

Perhaps you’re working in python and have a list of labels, and want to create an enum for them.

LABEL_1
LABEL_2
LABEL_3

The layperson would probably have to select each word, copy it, type = , type "" , then paste the word. I lost count of the keystrokes there, probably a million if I had to guess. THEN YOU HAVE TO DO IT AGAIN FOR EACH LABEL. And you’re probably using the mouse too. Yikes. All to get this:

class Labels(Enum):
LABEL_1 = "LABEL_1"
LABEL_2 = "LABEL_2"
LABEL_3 = "LABEL_3"

Let’s see how using macros can save some time, some keystrokes, and depending on the task, some sanity.

Macros being awesome

To start recording a macro you hit:

q + <letter>

Like I said you can save up to 26 macros using a different letter for each. In this case I chose q and you can see at the bottom of Vim it says:

recording @q

This means whatever commands you enter are being saved in the macro. What keystrokes did I save? It was:

^ - jump to the start of the line
yw - yank word (copy word)
A - append (enter Insert Mode) at end of line
--in Insert Mode I typed --
= ""
esc - exit Insert Mode to Normal Mode
p - put/paste (the word I had yanked)
q - to stop recording macro (always `q` regardless of which letter you're recording to)

Wow, she’s beautiful. Brings a tear to my eye.

And once it’s saved you run this magical macro with:

@q — @ runs a macro, q was the letter I saved it under

Pretty easy right? With macros you’re really only limited by your own ingenuity.

The only thing to point out about the macro I made, and with using them in most situations, is to keep them “general”. What do I mean by that? Check out the first command in the macro:

^ - jump to the start of the line

That’s actually super important because when you j down to the next line, without ^ if you yw you’ll only yank the last character since that’s where your cursor lies. Also the A command to append at the end of the line, regardless of the line length. In this case, all the lines have the same number of characters, so if you l to the end then i it would still work in this case, but not every case.

Like I said above the only limit to macros is what you can dream up!

Searching

We covered that you search with:

/<search term>

then you cycle through the matches with n

Okay you’ve found what you’re looking for, how to remove the highlighting?

:noh - no highlight

A common refactoring move may be to search and replace all the terms in a file. This would look like:

:%s/<search term>/<replace term>/g

This is really an augmented s — substitute command, but it’s within the search realm. Also since Vim is the best in the business you can search and replace within a specified range of lines:

:<start line>,<end line>s/<search term>/<replace term>/g

That’s a nice little move I legitimately haven’t come across in any IDEs.

Vim Mastery

This post was long and covered a bunch. I’ll be frank with you. You now know a lot of Vim, but also no Vim. This thing is feature-packed to the brim. By now we’ve covered the core-concepts of vanilla Vim. Like I’ve said many times, a lot of these things will get simpler/abstracted away with the use of plugins. But where would we be without the fundamentals?

Coming Up

Next, we’ll touch on customizing your Vim to your liking using the init.vim file (or .vimrc if you’re choosing not to use NeoVim). We’ll be able to change keybindings, change the look and feel of your Vim setup, and really start making it your own. It’s going to be epic.

Vim For Developers: Part 4 — Custom Configurations

--

--