There is also an accompanying Video!

If you are using Vim you are using registers. However, if you are like me, you might not understand the details, and this leads to confusion. So here's a breakdown of the 10 Vim Register Types.

  1. The unnamed register ""
  2. 10 numbered registers "0 to "9
  3. The small delete register "-
  4. 26 named registers "a to "z or "A to "Z
  5. Three read-only registers ":, "., "%
  6. Alternate buffer register "#
  7. The expression register "=
  8. The selection registers "* and "+
  9. The black hole register "_
  10. Last search pattern register "/

Note: Always refer to for more info :help registers

Before We Started

I think about interacting with Registers in two modes, normal mode and insert mode. Which mode you are in will affect how you interact with Registers.

Normal Mode: "<Register Key>

Insert Mode: <CTRL-r><Register Key>

So " triggers registers in Normal Mode and <CTRL-r> in Insert Mode.

Viewing Registers:



:reg 1

:reg a

:reg :

Clearing the Registers While Exploring

When exploring registers, it's useful to have a helper function to clear out all Vim Registers for easier inspection.

function ClearRegs() abort
  let regs=split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-"', '\zs')
  for r in regs
    call setreg(r, @_)

Stolen From Everyone's Favorite Mark

The Unnamed Register

What you are already using the Unnamed Register!

Anytime you are yanking or deleting text in Vim, you are interacting with the Unnamed register.

Things that Populate The Unnamed Register

  • d/D
  • c/C
  • s/S
  • x/X
  • y/Y

p/P pastes from the Unnamed Register

Numbered Registers

You also have 10 numbered Registers 0..9.

  • "0 is last yank
  • "1 is is last delete
  • "2 ... "9 are the previous deletes

Then every subsequent delete is placed in "1 the the previous delete is moved to the next numbered register, until you hit 9 and it drops off.

These numbered registers can be useful if you deleted something a couple commands ago, and want to reinsert it.

Named registers "a to "z or "A to "Z

These are all for you! You can put anything you like into the Named Registers.

Specify them as lowercase letters to replace their previous contents or as uppercase letters to append to their previous contents.

Also anytime you record a macro under a letter, you are actually saving the macro in one of the named registers! This allows you to edit that register, by simply rewriting the macro. When you type <Ctrl-r>a below it will insert the record macro for you to edit.

let @a='<Ctrl-r a>

This is an example of editing a macro saved under a, so it adds a , at the end of the line.

Also for fun, here's a script to populate all my letter macros with a random word. This way if I ever need a fancy word, I can just see what's in my macros.

function FillRegs() abort
  let regs=split('abcdefghijklmnopqrstuvwxyz', '\zs')
  for r in regs
    let word=system("cat /usr/share/dict/words | grep " . "^" . shellescape(r) .  " | shuf -n 1")
    call setreg(r, substitute(word, '\n$', '', 'g'))

Note: You will need to words under the folder /usr/share/dict/words for this to work.

Small delete register "-

This register contains text from commands that delete less than one line. Not something I really use. But hey its there and it's small!

I also did try and find the limit of how long a single line can be. It was able to handle 300,000+ lines, but I was not able to store the entirety of War and Peace. Also note, if the line is too long, it cuts off the end but does save the whole thing.

Finally for this confusion register, all actions you expect do not result in the Small Delete Register being populated.

s,  x,  X, c, C d and D work

S and dd do NOT work

If you know of any interesting use cases for this register, please reach out and share!

The 3 Read Only Registers

  1. . Last insert mode
  2. % Current File
  3. : Last command
".   Line 11
":   call ClearRegs()

These are useful for if want to rerun an insert or a long command, or need to interact with the current file name.

I often see % used in scripts to operate on the current file.

Also note there are some very useful filename modifiers you can use with the % Current File Register. See: :help filename-modifiers for details.


%:p -> Make file name a full path

%:h -> Head of the Filename

%:t -> Tail of the Filename

%:r -> Root

%:e -> Extension

Alternate file register "#

Last file of the current window

If there already was a current file name, then that one becomes the alternate
file name.  It can be used with "#" on the command line |:_#| and you can use
the |CTRL-^| command to toggle between the current and the alternate file.

Ctrl-^ is a nice thing for flipping between a test file and code under test.

Here's a couple Functions, for setting up a test file as you Alternative File.

nnoremap <leader>te :call OpenTests()<CR>

function! OpenTests()
  let test_file=substitute(expand('%:t'), '^', "test_", "")
  execute "rightbelow vsplit " .. test_file

function! AltTestFile()
  let test_file=substitute(expand('%:t'), '^', "test_", "")
  execute ":bad " .. test_file
  let @#=test_file

Note: if you want to write to the Alternative File Register, that file must have a buffer. That is what the :bad command is for the the AltTestFile function.

Expression Register "=

You can write and run quick expressions and have the result be pastable. This is a simple way to do some quick math,  "=108*420 press p and 45360 will be inserted.

Or you can call more complicated functions, even using system to escape vim.

=system('cat /usr/share/dict/words | grep ^a | shuf -n 1')

Selection registers "* and "+

Use these registers for storing and retrieving the selected text for the GUI.
When the clipboard is not available or not working, the unnamed register is used instead. What ends up here, depends on your OS. But in general, if I'm in a program other than vim, and I copy, both of these are getting filled.

I also have it set so, it's easy to copy from Vim, into another program.

set clipboard+=unnamedplus

See :help clipboard for more details.

Black hole register "_

When writing to this register, nothing happens.  This can be used to delete
text without affecting the normal registers.  When reading from this register,
nothing is returned.

It seems like people are stretching to use it.

The 2 uses cases I have, is using the Black hole register to delete another register. let @a=@_ and deleting a line, that I don't want saved in my register, like a password "_dd.

Last search pattern register "/

And last is appropriately the Last search pattern. Pretty obvious what it does, it's your last search!

Useful For:

  • Correcting a Search
  • Inserting the Last Search as you are typing
  • Using the Last Search for search and replace functions Search Mode

Search Mode: / CTRL-r /

Insert Mode:   CTRL-r /

Execute Mode: / CTRL-r /

Note: The Last Search Register is unique in as you you can't yank or delete into this register. But can be written in with :let.

Hopefully this helps or gives you some ideas. If you see an issue or have an interesting use of registers, please reach out!

Also this blog was inspired by a question from a Twitch Viewer, so if you want interact, and talk about all things Code, Vim, Linux, Programming etc. please join us over at Twitch!