Git Gud at Vim 1: Buffers

vim icon

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):

buffers and windows
    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

example of using vim :e with globbing
Here I'm using globbing to fuzzy find a path I never can remember...

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...

using `q:` to access the command history buffer
Here, I'm using 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:


🔖
Changelog
  • 2022-06-08 11:31:29 -0500
    Rename articles

  • 2020-06-18 14:26:02 -0500
    Move 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 -0500
    Update 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 -0500
    Hack 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 -0500
    Create 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 -0600
    Remove Tag: programming

    `code` is the same tag and has more coverage.

  • 2018-10-24 11:33:20 -0500
    Fix img with bad src

  • 2018-10-16 13:33:12 -0500
    Publish

  • 2018-10-15 15:22:44 -0500
    Add some corrections before the post

  • 2018-10-14 17:07:13 -0500
    Schedule the post out there for Tuesday

  • 2018-10-14 15:28:14 -0500
    Add another example to the blog post

  • 2018-10-12 19:43:58 -0500
    Fix typo, thanks @megalithic!

  • 2018-10-12 19:25:14 -0500
    Adjust the figures, do some more tweaking

  • 2018-10-12 19:20:28 -0500
    Add figure caption capability

  • 2018-10-12 14:28:08 -0500
    Small refactor of first article

  • 2018-10-12 14:22:25 -0500
    Add a caption

  • 2018-10-12 14:17:52 -0500
    Add neat svg animation

  • 2018-10-12 10:59:19 -0500
    Add emphasis

  • 2018-10-11 16:43:50 -0500
    Some refactoring and a new image

  • 2018-10-10 15:34:38 -0500
    More changes to the blog posts

  • 2018-10-10 14:44:42 -0500
    Add a line about command mode

  • 2018-10-10 13:54:06 -0500
    Add post number

  • 2018-10-10 13:37:43 -0500
    Change example in the globbing story

  • 2018-10-10 13:17:45 -0500
    Include message about globbing

  • 2018-10-10 12:34:03 -0500
    Fix typos

  • 2018-10-10 12:26:37 -0500
    Write vim post part 1