A Vim Journey: Clipboard, Buffers and Windows
Welcome back to the third part of my Vim journey! It took a little longer to get here than expected 😅. In the previous post, we explored Visual and Command-line modes. We can now select blocks of text and apply edits to many lines at once.
But editing one file is only part of the work. What happens when you yank something, delete another line, and suddenly paste the wrong text? How do you copy code into your browser? And how do you work with several files without opening a separate editor for each one?
These are the problems we will tackle in this post. I use Neovim, but the editing commands below work in plain Vim too. I will point out the differences where the setup matters. No plugins required for the editing workflow.
I also made a Vim cheatsheet you can keep handy while trying these commands.
Where Did My Copied Text Go?
Let’s start with something small. Put these lines in a scratch buffer:
keep this line
remove this line
paste below here
Place your cursor on the first line and press yy. Move down with j and delete the second line with dd. Your cursor is now on the last line. Press p.
You get remove this line. But you copied keep this line!
The reason is that deleting text also stores it in a register. A register is a place where Vim keeps text for later use. By default, p uses the unnamed register, which the delete just updated.
The text you yanked is still available in register 0. Undo the unwanted paste with u, then type:
"0p
That is a double quote, the number zero, and p, typed in Normal mode. The quote tells Vim that the next character names a register. Read it as “put from register zero.”
Register 0 holds your latest yank when you haven’t explicitly chosen another register. Ordinary deletes don’t replace it. This makes "0p useful when you have copied something and made a few edits before pasting.
Delete Without Replacing What You Copied
Sometimes you already know that you don’t want to keep the deleted text. Send it to the black hole register, _:
"_dd
This deletes the current line without changing the usual yank and delete registers. If you repeat the example with "_dd instead of dd, ordinary p still puts the line you copied.
The same idea works with the commands you already know:
"_diw- delete the word under the cursor without storing it"_ci"- change the text inside quotes without storing the old text
Keep a Snippet While You Work
For something you want to reuse even after more yanks, choose a named register:
"ayy
This yanks the current line into register a. Later, use "ap to put it. Ordinary yanks and deletes won’t overwrite a; explicitly writing to it again will.
You don’t need to learn every register right now. The unnamed register, 0, _, and one named register are enough to solve quite a few annoying moments. If you forget what you stored, run :registers to inspect them. The register documentation explains the rest when you need it.
Copying Between Vim and Other Applications
Vim’s internal registers also work across buffers in the same editor session. Copying into a browser or chat application needs access to the system clipboard.
When clipboard integration is working, use the + register:
"+yy- copy the current line to the system clipboard"+yafter a Visual selection - copy that selection"+pin Normal mode - put text from the system clipboard
The register prefix comes before the editing command. You are still using the same y and p you already know.
For linewise text, p puts it below the current line. For characterwise text, it puts it after the cursor. Use P to put before instead.
You may also see examples using "*. On X11, * normally refers to the primary selection, often pasted with the middle mouse button, while + refers to the clipboard used for ordinary application copy and paste. Other environments can treat them alike. Start with + for sharing text with other applications. See the clipboard explanation for the platform details.
When the Clipboard Commands Don’t Work
The command can be correct while the environment is missing the connection to your clipboard.
In Vim, check :version and :help clipboard. Available clipboard features depend on your Vim build and platform. In many builds, +clipboard versus -clipboard is a useful clue, but build features alone don’t guarantee access to a running desktop clipboard. Newer Vim versions also have additional clipboard mechanisms, so use the help bundled with your installed version.
In Neovim, run :checkhealth and inspect its clipboard/provider report. Neovim uses a clipboard provider, such as the macOS clipboard tools or a suitable Wayland/X11 tool. Its provider documentation explains what it can detect.
Over SSH, the remote editor doesn’t automatically have access to your laptop’s clipboard. Neovim includes OSC 52 support for compatible terminals, but terminal support, permissions, and multiplexers such as tmux affect whether it works. Copying out may work even when reading the clipboard back does not. See OSC 52 support before changing your configuration.
Your terminal’s paste shortcut is another route: it sends text to the editor rather than asking the editor to read +. Enter Insert mode before using it. This can work even when "+p cannot, though behavior depends on the terminal and editor’s paste support.
One setting you will probably encounter is clipboard=unnamedplus. It redirects ordinary unnamed-register operations to the system clipboard, including deletes and changes. That is convenient if you want it, but it can also replace something you copied in another application. Try explicit "+y and "+p first so you can decide whether that behavior suits you.
Working With More Than One File
Let’s say you are editing app.js and want to look at utils.js. You don’t need another editor process. Run:
:edit utils.js
The current window now shows utils.js. Your earlier file is still in the buffer list. Run :ls to see it.
This is where the terminology helps:
- A buffer holds the text you are editing in memory
- A window shows a buffer
- A tab page holds a layout of windows
Several windows can show the same buffer, and a buffer doesn’t need to be visible all the time. Saving with :w writes its text to disk. The multiple-files tutorial is a useful reference for this workflow.
Switching Buffers
These commands cover the basics:
:ls- list buffers;%marks the current one and+marks unsaved changes:buffer 2- switch to buffer number 2, if that is the number shown by:ls:buffer utils- switch using a unique part of an existing buffer’s name:bnextand:bprevious- move through the buffer list:buffer #- return to the alternate buffer in this window, useful for bouncing between two files
You can also use filename completion when opening files: type :edit ut, then press Tab to complete a matching filename. :edit opens a file; :buffer selects an existing buffer.
What About Unsaved Changes?
Plain Vim may refuse to switch away from a modified buffer with a “No write since last change” message. Save with :w and try again.
If you want to leave changes unsaved while working elsewhere, use:
:set hidden
This lets modified buffers remain in memory when they are no longer displayed. Neovim enables this by default; plain Vim normally doesn’t. Your configuration may change either default.
Hidden doesn’t mean saved. Check :ls, return to your changed buffers, and save them before exiting. Don’t add ! to dismiss a warning unless you understand what will happen to your changes. See Vim’s hidden option and Neovim’s defaults.
Seeing Two Files at Once
Sometimes switching back and forth is inconvenient. Open the second file in a split:
:vsplit utils.js
This creates a side-by-side layout. Use :split utils.js for windows stacked above and below each other.
To move between them in Normal mode, press Ctrl-w, release it, then press a direction:
h- leftj- downk- upl- right
For example, Ctrl-w then l moves to the window on the right. Ctrl-w then w cycles through windows, and Ctrl-w then = equalizes their sizes.
Run :vsplit without a filename and both windows show the same buffer. You can keep a function’s definition visible in one while reading its usage farther down in the other. Edits appear in both because they share the same text. The split-window tutorial covers more layouts.
Closing a Window or Removing a Buffer
Use :close when you are done with a split. It closes the window without removing the buffer from the buffer list. It won’t close the last window, and it can refuse if unsaved changes cannot be hidden.
Use :bdelete when you want to remove the current buffer from the listed buffers. It doesn’t delete the file on disk, but it can also close windows displaying that buffer. Save first if you want to keep changes; :bdelete! discards them.
For the precise behavior, including hidden buffers, see the window and buffer reference.
And Tabs?
A tab page is useful when you want another window layout. For example, one layout could show implementation and tests side by side, while another shows documentation.
:tabnew creates a tab page; gt and gT move to the next and previous ones. Buffers are shared across tab pages. You don’t need a tab for every file to keep that file available.
Putting It All Together
Try this with disposable practice files:
- Open
app.jsand yank a useful line with"ayy - Save any changes with
:w, then openutils.jsusing:vsplit utils.js - Put the saved line with
"ap, then edit it for its new location - Select the result in Visual mode and type
"+yto copy it outside the editor, if clipboard integration is available - Save
utils.jswith:w, then run:close - Run
:ls, findutils.js, and return to it with:buffer utils
You have copied between files, shared text with another application, and closed a view without losing track of the file.
Conclusion
There are quite a few commands here, so don’t try to memorize all of them at once. Start with the problem you actually run into: "0p when a delete replaces your yank, "+y when you need to share code, or :vsplit when you need two files in front of you.
As with the previous parts, the useful thing is knowing that Vim has a way to do it. The next time you catch yourself reaching for a workaround, try one of these commands instead. That’s how they gradually become part of your workflow.
In part 4, we’ll bring the series together with a recap and cheatsheet, so you have the commands from these posts in one place when you need a reminder.