Follow @learnvim for more Vim tips and tricks!
Vim has never been like most editors. I've used different editors (Notepad++, Atom, VSCode, and yes, emacs, briefly). Most editors use tabs and windows system. Vim has buffers, windows, and tabs. Some of these abstractions Vim use are different.
If you are new to Vim, I will explain what buffers, windows, and tabs are. I will also show how to use them efficiently.
Table of Contents:
- Vim buffers
- Vim windows
- Vim tabs
- Thinking in 3D
- Using buffers, windows, and tabs efficiently
- Resources
Before we start, if you haven't, add set hidden
in your ~/.vimrc
and source it. Without this option, whenever a changed buffer goes to "hidden", Vim will prompt you to save the file. For more information about this setting, check out this article and :h hidden
.
Vim buffers
A buffer is the in-memory text of a file.
When you open a file in Vim, it creates a new buffer. Do this from your terminal:
vim file1.js
After running this, Vim creates one buffer for file1.js
. This buffer is stored in-memory.
Exit Vim. Back to console, run:
vim file1.js file2.js
Vim creates 2 buffers: one for file1.js
and one for file2.js
. You are probably still seeing file1.js
.
However, right now Vim has 2 buffers. You can see all buffers with :ls
(or :buffers
, or :files
).
There are several ways to go between file1.js
buffer and file2.js
buffer:
-
:bnext
to go to next buffer (:bprev
to go back) -
:buffer
, then type the name. Vim can autocomplete with<Tab>
-
:bufferN
where N is buffer number.:buffer2
for example, will jump to buffer #2. - Jump between your last 'position' with
<Ctrl-O>
and<Ctrl-i>
. This is not buffer specific, but it works. - Toggle between previous file with
<Ctrl-^>
For method #2, you can combine buffers list with buffer name. For example, with this mapping, pressing <Leader>b
will display my buffers and types :buffer<space>
command. All that is left for me to do is typing the buffer number or buffer name (that Vim can autocomplete).
:nnoremap <Leader>b :buffers<CR>:buffer<Space>
Once a buffer is opened, it remains in your buffers list. We have two buffers opened: file1.js
and file1.js
buffers. Still in the same vim session, if we want to open a new file, we can do :e file3.js
. If we check with :ls
, we'll see that we have 3 buffers.
You can type :bdelete
to close a buffer. To be honest, in my years of editing with Vim, I almost never needed to delete buffers.
The way I see it, buffer is like Z axis in X-Y-Z coordinate. Imagine X axis to right, Y axis to top, and Z axis towards screen. Your buffers files are lined up in the Z axis. You can traverse the Z axis one file at a time with :bnext
/:bprev
. You can jump to any coordinate in Z axis with :buffer <filename>
. The number of file buffers you have is how long your Z axis is. Vim makes it almost frictionless to travel anywhere along this Z axis.
Vim windows
A window is a viewport on a buffer. In Vim, you can have multiple windows opened.
From your console, run this again:
vim file1.js
What you are looking at the screen is one window that displays buffer file1.js
. Window is what you are seeing buffers through.
Exit Vim. In console, run
vim file1.js file2.js
We've seen this many times now. This time, we have two buffers and still one window.
Don't quit vim yet. Run:
:split file2.js
You are looking at two windows. It's kind of hard to see the texts on bottom window, but the bottom one says file1.js
(and top one file2.js
). The top window is a viewport for buffer file2.js
, the bottom window is a viewport for buffer file1.js
.
Remain in this vim session - don't quit yet. Run:
:vsplit file3.js
You are now seeing three windows. Top left window displays file3.js
buffer. Top right window displays file2.js
buffer. Bottom window displays file1.js
.
I hope you are starting to see the difference between vim buffers and windows. Don't worry if you aren't - take your time. It took me a while to understand it when I was learning this.
You can have multiple windows displaying one buffer. Right now I am still on top left window that views file3.js
buffer. I will type:
:ls
:buffer 2
Now both top left and top right windows are displaying file2.js
buffer (bottom window still displays file1.js
buffer). If I start typing on top left, you'll see that both top left and top right window are changing as I type.
To close current window, you can run <Ctrl-W>+C
. Alternatively, you can do :quit
. When you close a window, a buffer will still be opened (check :ls
).
Some useful shortcuts for window:
<Ctrl-W>+v # Opens a new vertical split
<Ctrl-W>+s # Opens a new horizontal split
<Ctrl-W>+c # Closes a window
<Ctrl-W>+o # Makes current window the only one on screen and closes other windows
<Ctrl-W>+h/j/k/l # Moves the cursor to left/bottom/top/right
Some useful Ex commands:
:vsplit <filename> # Split window vertically
:split <filename> # Split window horiontally
:new [filename] # Create new window
For more, check out :h window
.
Vim tabs
A tab page is a collection of windows. In Vim, a tab has different meaning than most text editors. In most text editors (and modern browsers), a tab usually means an open file/ page. When we close it, that file/page goes away.
In Vim, a tab does not represent an open file. We just learned that vim saves opened files in buffers. When we close a tab in vim, the files in that tab are still stored in buffers. A tab can have one or many windows. Think of tabs like layouts or templates.
Let's try it. In console:
vim file1.js
Let's open file2.js
in new tab:
:tabnew file2.js
More tabs navigation:
:tabnew file.txt # open file.txt in a new tab
:tabclose # Close current tab
:tabnext # Go to next tab
:tabprevious # Go to previous tab
:tablast # Go to last tab
:tabfirst # Go to first tab
You can also run gt
to go to next tab page in Normal mode.
To start vim with multiple tabs, you can do this from console:
vim -p file1.js file2.js file3.js
Thinking in 3D
Moving between windows in Vim is like traveling along X-Y axis in cartesian coordinate. We are moving two-dimensionally. We can move to top, right, bottom, left with <Ctrl-W>+h/j/k/l
.
Earlier I said that Vim buffers are like Z axis. Inside each window, you can move along the Z axis with buffer navigation. When we combine window movement with buffer traversal, we are moving in three-dimensional space.
Each window can view any of our buffers.
This X-Y-Z movement is possible thanks to Vim's window and buffer features.
Using buffers, windows, and tabs efficiently
To learn how to use buffers, windows, and tabs efficiently is to understand what they are designed to do.
Use buffers to open up all required files to get current task done. It may be eight or eighty buffer files. Having many buffers opened doesn't effect spatial distribution. Vim has designed switching file buffers to be frictionless. Use that to fly between buffers.
Use windows when you need to view multiple buffers. Like when diffing files, referencing codes, or following code flows.
Use tabs when working on different projects. Like one tab for server codes and one tab for client codes.
In most code editors there are 2 abstractions in their workflows: windows (ex: split screen) and tabs. In Vim there are 3: buffers, windows, and tabs. When I started using Vim full-time, it required a significant paradigm shift. My personal suggestion is to take your time to use it the way they were designed first. If after you've tried it and you still don't think it's for you, use the process that suits you most.
In addition, you can look at plugins such as ctrlp.vim or fzf.vim to boost your workflows.
Ultimately, do what works for you. Just because a certain feature was designed to for X doesn't mean everyone should do X. Feel free to experiment around and find your best workflow.
This is a good place to stop. Thank you for reading. Happy coding!
Top comments (12)
Is there any way we can have buffers containerized in tabs.
I mean suppose I open 3 buffers in vim.
then I create a new tab and open 3 completely new buffers in that tab.
Now if I :ls it shows all the buffers, the behaviour that I expect or think-of-as-better-one is that if I :ls in second tab, only buffers opened in that tab are shown.
And first tab buffers are only shown for the first tab on :ls.
Though it should be configurable, if one want to access buffers from the first tab then some variant of :ls or some other command should give me all the buffers so that I can use vim's default behaviour.
what do you guys think of it?
Should it be this way, as I described or should this be left to tmux+new-vim-instance?
I never thought of containerizing buffer in tabs before, but that's a good point. I personally don't use Vim tabs. I may have multiple Vim instances in different Tmux windows, so they are automatically containerized.
I think it comes down to a design decision. The people who wrote Vim (Bram etc) probably decided that buffers are shared objects instead of tab-specific objects. It could've gone either way haha.
Again, this is a really good point that you brought up!
vim-ctrlspace is a plug-in to containerize buffers in tabs.
Will look into that.
from a users perspective I think this should be configurable, for the folks who do not have tmux available (like I on my employer's windows machine).
Or I think we could make a plugin that does this somehow. I don't know the details of it, but I think it might be possible.
Super helpful -- thank you!
This was useful. Getting familiar with the terms really helped me back when I was using Emacs. Now I'm learning VIM and this is a good reference.
Thanks Nick! Appreciate it. If you find how I can present my article better, please feel free to put it in comment :)
Any feedback will be highly coveted.
Use of
ctrl-p
withfzf
to switch buffers/tabs/files is a superb tip, I'd forgotten I had that set up. So much easier & faster than:tabn
etc.Nice! Looks like it was kind of article I needed so much.
Super helpful! Thank you.
I still don't get it. What's the practical usage of buffers?
This is one of the best explanations I've ever seen about anything (not only VIM resources)!! The X/Y/Z axis thinking makes everything soooooo much cleaner!