5 Minutes Vim: Copying, Cutting, Pasting, Registers and How to Tame Them
In this 5 minutes of Vim goodness we’ll learn how to effectively copy, cut and paste things in Vim by taking advantage of Vim’s registers and a cool plugin. Here we go!
Copy and paste. Doesn’t sound like much excitement, does it? You are probably accustomed to use your mouse to perform some text selection, copy or cut it and then paste it somewhere else. And that is it. Not so much to be excited about.
Vim spices up copying, cutting and pasting in a couple of ways:
- It gives you new shiny operators and commands you can use in combination with all the motions you’ve learn thus far
- It provides a handful of registers where you can save stuff for later pasting which can enable interesting workflows
The two main commands for copying and pasting are y
and p
. Why y
and not c
for copy, you may wonder? Well, if you are familiar with Vim you may know that c
is already taken, it is the change command. And thus, the vi engineers had to come up with a suitable way to describe copying and settled on the colourful name of yank (because engineers are far more playful than one would think at first sight). So in Vim you don’t copy stuff, you yank it (great naming… So visceral). p
stands for put and therefore in Vim you yank some text from somwhere and put it some place else. If you’re accustomed to think of p
in terms of pasting then feel free to use whichever mnemonic makes you happy.
y
is an operator. You can combine it with any of the motions and text-objects we’ve learned to yank stuff to your heart’s content:
yl
yanks a letter,yaw
yanks a word,yas
yanks a sentenceyi(
yanks everything within(
and so on…
If you double y
as in yy
you get a linewise operator like dd
and cc
and yank a whole line. The Y
command also yanks a complete line.
In order to paste things you use the p
command and its variants:
p
pastes something after the cursorP
pastes something before the cursorgp
same asp
but puts the cursor after the pasted selectiongP
same asP
and puts the cursor after the pasted selection
Pasting in Vim is kind of special and the behavior of p
and P
depend on whether you’ve yanked characters or lines. If you’ve yanked characters then pasting will put those characters after or before the cursor (no surprises there). If you’ve yanked lines, however, pasting will put those lines after or before the line where the cursor is resting on. This behavior may sound weird at first but it makes a lot of sense in practice.
Imagine that you are contemplating this powerful extract from an ancient text:
Hither came Conan, the Cimmerian, black-haired, sullen-eyed, sword in hand, a thief, a reaver, a slayer, with gigantic melancholies and gigantic mirth, to tread the jeweled thrones of the Earth under his sandaled feet.
And you want to add more intensity to this passage you may decide to yank the the
particle and sprinkle it here and there:
v
Hither came Conan, the Cimmerian, black-haired, sullen-eyed, ...
Start by jumping to the the particle with f,w
:
v v
f,w Hither came Conan, the Cimmerian, black-haired, ...
Then yank the word with yaw
, jump to the next location were to put the with ;w
and paste with P
:
v v
;w Hither came Conan, the Cimmerian, the black-haired, ...
The jump to the next location again with ;w
and type .
to repeat the last change:
Hither came Conan, the Cimmerian, the black-haired, the sullen-eyed, ...
Want to duplicate a line instead? It is as easy as typing yyp
. Imagine that you have an array literal in JavaScript and it’s filled with magical items of wonder:
const chest = [
{name: 'sword', weight: 2.1, state: 'well kept'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
];
And now you want to add some more items to this chest. You can use any of the existing items as a template and type yyp
to duplicate it:
const chest = [
{name: 'sword', weight: 2.1, state: 'well kept'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
];
Then type ci'
to change its name to something else:
const chest = [
{name: 'sword', weight: 2.1, state: 'well kept'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'scepter of fire', weight: 0.4, state: 'worn out'},
];
Want to n-plicate a line? (Yes, I’m pretty sure that’s a real word) It is as simple as typing yy{count}p
. Yes! Counts also work with yank and pasting because they’re just commands! Let’s retry the example above but this time type yy5p
:
const chest = [
{name: 'sword', weight: 2.1, state: 'well kept'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
];
Wow! Impressive, isn’t it?
Ok. So if y
, the yank command, copies stuff… How do you cut things in Vim? Aha! Here comes a surprise!
Cutting Stuff In Vim
You may be familiar with the d
(delete) and c
(change) commands in Vim? As their name indicates they let you delete and change text in Vim. A lesser know fact is that, in addition to deleting and changing text, they also cut it.
Imagine that in addition to the chest
we had earlier we now have a brave adventurer ready to explore the world and confront its perils. Sadly, our adventurer has little and lacks many of the tools of the adventuring trade she’ll need to survive:
const chest = [
{name: 'sword', weight: 2.1, state: 'well kept'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
];
const sonja = {
name: 'Sonja',
inventory: [
],
};
Let’s give her some help and move the well kept sword from the chest into her inventory:
v
const chest = [
{name: 'sword', weight: 2.1, state: 'well kept'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
];
We type 2jdd
to jump two lines down and delete (and cut) our sword:
const chest = [
v
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
{name: 'rusty dagger', weight: 0.4, state: 'worn out'},
];
Then /in<ENTER>
to move our cursor on to of the in in inventory
:
const sonja = {
name: 'Sonja',
v
inventory: [
],
};
And now we type p
and we’re ready for adventure:
const sonja = {
name: 'Sonja',
inventory: [
v
{name: 'sword', weight: 2.1, state: 'well kept'},
],
};
Now you can save the file and if you have an autoformatter setup it’ll fix your indentation or you can type ==
to manually format that line.
What more can you do with cutting and pasting in Vim? Have you ever made a typo and need to swap two characters? Type dlp
(or xp
). Want to swap couple of lines? Type ddp
. Want to swap a couple of paragraphs? Type dapp
.
Excellent! So now you’ve boosted your knowledge with yanking, cutting and pasting in Vim. But there’s yet one crucial element left that we haven’t even touched on yet: The mighty registers.
A wonderful way to illustrate the impact of registers is swapping two values within Vim. I do some variant of this task incredibly often.
Imagine that you have a couple of CSS variables that represent a couple of colors in a color theme of a beautiful website you’ve just designed:
:root {
--red: #0F0;
--green: #F00;
}
You quickly notice the colors are wrong. You’ve mixed them. The red is the green and the green is the red. Oh no! What to do!?
So you try swapping them using what we’ve just learned. You type /#<Enter>
and put the cursor on top of the hexadecimal value:
--red: #0F0;
^
You cut it with daW
:
--red:
^
Type n
to move to the next hex value, delete it with daW
and try to paste the red with p
, but…
:root {
--red:
--green: #F00;
}
What!? That is so not what I expected to happen. What did I do wrong?
You may have noticed the issue with this swap as you were following the example but if you haven’t I will tell you: The problem is that delete also cuts. When we deleted the hexadecimal value for the green color in the last step we literally overwrote the red hexadecimal value. That’s why when we typed p
at the end the pasted characters where #F00
and not #0F0
as we initially expected.
But what did we overwrite exactly? Most systems have the concept of a clipboard, which is a place where you put the stuff that you copy and cut. Well Vim doesn’t have a clipboard, Vim has registers.
Vim’s Registers
Vim registers are the equivalent of a clipboard, but since you have lots of them, they’re that much powerful.
When we use commands like y
, d
, c
and p
we’re interacting with Vim’s unnamed register. You aren’t limited to that one though, you have 26 named registers, one for each letter of the alphabet, that you are free to use as you see fit.
The way that you explicitly access a given register is by prefixing a command with "[a-z]
. So:
"ayy
yanks a line into thea
register"add
cuts a line into thea
register"ap
pastes from thea
register
Using the lowercase name of a named register overwrites its contents, whereas if we use the capitalized version of that name we will append whatever we yank or cut into the register (this can be really useful when we want to collect text into a register for later pasting).
Using named registers offers one way to solve the problem that ailed us earlier when we were swapping colors. Instead of using the unnamed register alone we could’ve used it in combination with the a
register:
/#<Enter>
to move the cursor to the first hex valuedaW
to cut the green color value in the unnamed registern
to move to the second hex value"adaW
to cut it into thea
named registerp
pastes the first hex value in the write placek
to go up"ap
which now pastes from thea
register and we’re done
Excellent! If you ever lose track about which register you have put stuff in, you can rely on the :registers
(or :reg
) command. :registers
will print the value of all registers into a buffer. If you’re only interested in the contents of a particular register you can also specify it as an argument. For instance, typing :reg a
after the previous example would result in the following:
--- Registers ---
"a #F00;
Another useful way to interact with named registers is by taking advantage of the fact that capitalized named registers append to the register instead of replacing its contents. For instance, we could build an outline of a markdown document by continously appending headers to the a
register:
/^#.*<ENTER>
to jump to the next header"ayy
to copy the header into thea
registern
to jump to the next header"Ayy
to append the header to the contents of thea
register- then
n
and"Ayy
until you’ve gathered all the headers you want "ap
to paste the outline of the mardown document
In addition to the named and unnamed registers there are more registers that will be useful from time to time: The yank register (0
), the delete registers (1-9
) and the black hole register (_
).
The yank register 0
holds the last bit of text you yanked. That is, it only stores text you have yanked with the y
command and lives completely unperturbed by whatever happens with cutting operations like d
or c
. This can be really useful if you want to rename a variable or other pieces of text. Using the yank register offers yet another alternative way to swap values.
The delete registers 1-9
are nine registers that contain the last 9 pieces of text you cut or deleted. They work as a queue where every time you cut something it gets stuck in the queue at position 1
, whatever was in 1
is pushed to 2
and so on. The delete register can be really useful when you happen to delete something in the past and you want to bring it back (in fact, it just saved me from losing a beautifully written parapraph). Just like the named and yank registers, you can take advantage of delete registers as an alternative way to swap values.
The black hole register has a fitting name because it truly allows you to delete text into oblivion. A nice way to avoid overwriting the unnamed register is to prefix the delete operator with the black hole register: For instance, type "_daw
to blast a word into oblivion for ever and ever.
Copy and Pasting In and Outside Of Vim
Everything we’ve discussed thus far only applies to the world of Vim. All the commands and registers that we’ve seen allow you to yank, cut and paste text only within the confines of Vim. What happens when you want to copy to or paste from outside of Vim? For instance, when you find a wonderful piece of code on StackOverflow and want to try it in a program?
There’s two registers that work as an interface between Vim and the outside world: The +
and the *
registers.
- You can use the
+
register to interact with the system clipboard in Windows, Mac and Linux - You can use the
*
register to interact with the primary clipboard in Linux, and also the system clipboard in Windows and Mac (since these two only have the single clipboard)
One thing that I find super convenient and that I’d advise you to do is to have your system clipboard use the unnamed register. That way you can seamlessly copy and paste between Vim and the rest of your computer, taking advantage of the fastest commands d
, c
, y
and p
, and avoiding the need to specify the +
and *
registers.
If you are using Neovim you can enable this behavior in your vimrc like so:
set clipboard+=unnamedplus " use system clipboard
Likewise in traditional Vim:
set clipboard=unnamed " use system clipboard
Take a look at :h clipboard
for more information.
Pasting in Insert mode
All of this article has focused on how you can copy and paste things from within Normal mode. Sometimes however, it can be helpful to paste things within Insert mode. Earlier you learned how you can paste using the p
command but that won’t do in Insert mode (it would just insert the letter p
). What to do? Well, in some instances (f.i. gvim and mvim) you may be able to use your system copy/paste key bindings, but you can always rely on <C-R>{register}
to paste text from any given register
:
<C-R>a
pastes the contents of thea
register<C-R>"
pastes the contents of the unnamed register<C-R>0
pastes the contents of the yank register.
And yes, you’ve guessed it right, the R
stands for Register. Use that as a mnemnonic and you’ll never forget how to paste things in Insert mode.
A Really Cool Plugin To Simplify Working With Registers in Vim
Before we part here is a really cool plugin that helps you work with register in Vim: vim-peekaboo. This plugin extends "
and @
in normal mode and <CTRL-R>
in insert mode so you can see the contents of the registers as you are about to perform a copying, cutting or pasting operation:
Cool right?
And that’s all for today! Take care and have a wonderful day!
Written by Jaime González García , dad, husband, software engineer, ux designer, amateur pixel artist, tinkerer and master of the arcane arts. You can also find him on Twitter jabbering about random stuff.