Git Gud at Vim 1: Buffers

This is a write-up of a series I presented to a small group in 2018. To see all the articles, see the link below or find more vim related articles.
I'm doing a four part little workshop in Birmingham over lunch for some vim enthusiasts, and I thought I'd record my rough outline as a blog post for the rest of the internet.
I've been a user of vim for about ten years, and I'm still constantly learning new things that I didn't know before... it's a super fun tool. I got into it originally as a step in reducing the number of tools I used as part of work/school. I had eclipse for java homework, homesite+ for web development work, textmate for c homework... and my friend Tom had challenged me to learn one editor well. I chose vim, and I haven't regretted it one bit. I can't stop using it... it's too powerful. It would be like giving up superpowers.
Vim was designed to edit text, which is what most of us spend a lot of our time doing. It is also installed on pretty much every *nix system out there, so if your job ever involves ssh'ing into a server (and it will!) vi will be there, so I think everyone should have at least a rudimentary knowledge.
Concepts
How vim thinks about files and buffers (from :help buffers
):

Summary: A buffer is the in-memory text of a file. A window is a viewport on a buffer. A tab page is a collection of windows.
It's worth briefly thinking about how totally different this is from most other text editors we use! Most of the time, we open files into tabs... and when we close that tab, the file is closed and we lose all the undo history, state... even unsaved changes. If we try to open the same text file twice, the application will usually present you with the same window on the file. A file in most editors is exactly the same as the view on the file.
Vim doesn't think this way exactly. As you open files in vim
using :e
or by passing the filename as an argument when you start vim
(vim foo.txt
), those files are loaded in memory as Buffers. Usually, that
file will also be presented to you in a single Window, which is where we
work. We can split the current Window (using :vs
or :sp
) which without an
argument will open a Window on the current Buffer... two views on the same
file. You can of course look at multiple files in splits, but this is
important: Multiple Windows, open on the same buffer. It's a viewport, a
literal Window on the Buffer, not the file itself like it is in Textmate. I can
have one Window open on the top of a long .c file to look at the includes, and
one Window 300 lines down the file looking at a particular function, both
editing the same buffer.
Very powerful. But you may not realize it yet... Just hold those definitions in your mind as we go forward.
Commands
We are going to talk more about Command mode later, but for now, to enter a
command you just type :
while in Normal mode and start typing the command...
tab completion works and all that just like your terminal.
:e
This lets you :e[dit]
files... but it has a few tricks up it's sleeve:
For instance, you can open .zip and other archive files, and see what's inside!
Network capabilities... you can even edit over ftp and ssh using :e ftp://
and :e ssh://
. (Vim has a powerful tool called netrw
that powers all the
reading, writing, browsing of files over network or locally.)Try :e
http://tired.com/
to see the source code of a website. If you wonder if vim
can open it or work over some connection... the answer is probably yes. :P
One of the powerful things you can do with :e
is you can use globbing to edit
a file deep in a file structure. For instance, the last time I opened the
firmware keymap for my keyboard, I used :e **/*fullmods/keymap*
to open
layouts/community/ortho_4x12/fullmods/keymap.c
. Very powerful... and yes, it
even works over :netrw
, so you can use it over ftp!
:e
has a lot hidden inside it thanks to vim's handling of files and netrw
,
so if you are having difficulty moving through your project, do some reading.
There's probably a better way.
:ls
This lists your currently open buffers, along with some useful flags to let you know their current state (current buffer, modified, unmodified, read-only, etc.)
:b[uffer]
This lets you switch the window between open buffers... either by the number
coming from :ls
... or by a loose fuzzyfind string. :b css
-> "style.css" if
that's a buffer you have open.
:bn[ext]
and bp[revious]
If you want you can go back and forth between two files. I used to use these a
lot to move between my open buffers, until I learned I can jump right to the
buffer I want using :b
, I use it still less since I use the jumplist
which we'll talk about in a later post.
:bd[elete]
This will unload a buffer and remove it from the buffer list. I mostly use this
if I accidentally opened a lot of files trying to find the file I actually
need to edit, and I want to avoid collisions when switching buffers using
:b <pattern>
. I'll pass some patterns or buffer indexes to it to close the
buffers I don't want.
(Nearly) Everything is secretly a buffer...
q:
to access the command history buffer, then
using reverse search (?
) to find a previously run command and repeat
it!Why is it soooo important to understand the idea of Buffers vs. Windows vs.
Tabs? Because so much of vim is actually a buffer in disguise. Your search
history? Actually a buffer (you can see it using q/
). Help system? It's a
buffer. The quickfix list that's returned from a plugin? It's a special
buffer. Understanding what a buffer is and how to move and interact with it
will help you interact with nearly every other part of vim.
Further Reading:
- Where vim came from
- Buffers, Windows, Tabs... Oh My! Part 1: Vim Buffers
- (I'm using asciicast to record terminals, and svg-term-cli to make the animated svg)
Changelog
-
2022-06-08 11:31:29 -0500Rename articles
-
2020-06-18 14:26:02 -0500Move everything to CST
Don't know why I didn't do that before. It caused _no_ end of
problems. -
2020-06-14 15:51:50 -0500Update articles with series and series partials
After the refactor, needed to move the series metadata to the actual
name. -
2020-06-08 12:17:07 -0500Hack together a series page
I'm basically hacking this into the "tags" system... if you have a tag
named "series-<rest of tag>", it changes the tag page to a "series" page
that also uses the same partial as a series post. -
2020-06-08 10:48:51 -0500Create series partial
I tend to write series blog posts, and I have one coming up... so I have
refactored how I used to do series to test it out. -
2019-11-14 19:21:38 -0600Remove Tag: programming
`code` is the same tag and has more coverage.
-
2018-10-24 11:33:20 -0500Fix img with bad src
-
2018-10-16 13:33:12 -0500Publish
-
2018-10-15 15:22:44 -0500Add some corrections before the post
-
2018-10-14 17:07:13 -0500Schedule the post out there for Tuesday
-
2018-10-14 15:28:14 -0500Add another example to the blog post
-
2018-10-12 19:43:58 -0500Fix typo, thanks @megalithic!
-
2018-10-12 19:25:14 -0500Adjust the figures, do some more tweaking
-
2018-10-12 19:20:28 -0500Add figure caption capability
-
2018-10-12 14:28:08 -0500Small refactor of first article
-
2018-10-12 14:22:25 -0500Add a caption
-
2018-10-12 14:17:52 -0500Add neat svg animation
-
2018-10-12 10:59:19 -0500Add emphasis
-
2018-10-11 16:43:50 -0500Some refactoring and a new image
-
2018-10-10 15:34:38 -0500More changes to the blog posts
-
2018-10-10 14:44:42 -0500Add a line about command mode
-
2018-10-10 13:54:06 -0500Add post number
-
2018-10-10 13:37:43 -0500Change example in the globbing story
-
2018-10-10 13:17:45 -0500Include message about globbing
-
2018-10-10 12:34:03 -0500Fix typos
-
2018-10-10 12:26:37 -0500Write vim post part 1