Vim Registers
Register types and advanced register usage.
Register Types
" DEFAULT REGISTER (unnamed) - catches everything
"" " Last delete OR yank
p " Paste from default register
"0p " Paste from yank register (safer!)
" YANK REGISTER - only yanks, never deletes
"0 " Last yank (preserved across deletes!)
yiw " Yank word → goes to "" AND "0
dd " Delete line → goes to "" only
"0p " Still pastes the yanked word!
" NUMBERED REGISTERS - delete history stack
"1 " Most recent delete (full lines)
"2 "3 "4 "5 "6 "7 "8 "9 " Previous deletes (FIFO queue)
"1p " Paste most recent delete
"1pu.u.u. " Walk through delete history
" SMALL DELETE REGISTER
"- " Deletes less than one line
diw " Delete word → goes to "-
x " Delete char → goes to "-
" BLACK HOLE REGISTER - discards text
"_ " /dev/null for vim
"_dd " Delete line, keep registers intact
"_ciw " Change word, don't touch registers
Named Registers
" LOWERCASE NAMED REGISTERS (a-z) - replace content
"ayy " Yank line into register 'a'
"ap " Paste from register 'a'
"bdiw " Delete word into register 'b'
" UPPERCASE NAMED REGISTERS (A-Z) - append content
"Ayy " APPEND line to register 'a'
"Add " APPEND deleted line to register 'a'
" Build a collection across file
"ayy " Start with first match
/pattern
"Ayy " Append next match
n"Ayy " Keep appending
"ap " Paste all collected lines
" Infrastructure example: collect all error lines
:g/ERROR/yank A " Collect all ERROR lines
"ap " Paste collected errors
System Clipboard Integration
" CLIPBOARD REGISTERS
"+ " System clipboard (Ctrl+C/V)
"* " Primary selection (X11 middle-click)
" Check clipboard support
:echo has('clipboard') " 1 = supported
" Copy to system clipboard
"+yy " Yank line to clipboard
"+y$ " Yank to end of line to clipboard
"+yiw " Yank word to clipboard
V"+y " Yank visual selection to clipboard
" Paste from system clipboard
"+p " Paste after cursor
"+P " Paste before cursor
"+gp " Paste, cursor at end
" Make clipboard default (vimrc)
set clipboard=unnamedplus " Use system clipboard as default
" X11 primary selection (middle-click)
"*y " Yank to primary selection
"*p " Paste from primary selection
" macOS: pbcopy/pbpaste integration
:w !pbcopy " Copy whole buffer to clipboard
:r !pbpaste " Paste from clipboard
Special Read-Only Registers
" SEARCH REGISTER
"/ " Last search pattern
:echo @/ " Print last search
:let @/ = "pattern" " Set search (for scripts)
" COMMAND REGISTER
": " Last command-line command
@: " Execute last command again
:echo @: " Print last command
" INSERTED TEXT REGISTER
". " Last inserted text
".p " Paste last inserted text
Ctrl+A (insert mode) " Re-insert last inserted text
" FILENAME REGISTERS
"% " Current filename
"# " Alternate filename (last file)
:echo @% " Print current filename
:echo expand('%:p') " Full path
:echo expand('%:t') " Just filename
:echo expand('%:h') " Just directory
" EXPRESSION REGISTER (powerful!)
"= " Expression register
"=system('date')p " Insert command output
"=5*42<CR>p " Insert calculation result
Ctrl+R = (insert mode) " Insert expression result
Register Operations
" VIEW REGISTERS
:reg " Show all registers
:reg a b c " Show specific registers
:reg + " Show clipboard register
:reg 0 1 2 " Show yank + delete history
" CLEAR REGISTERS
:let @a = "" " Clear register 'a'
:let @+ = "" " Clear clipboard
:let @/ = "" " Clear search highlight
" SET REGISTER CONTENT
:let @a = "text" " Set register 'a'
:let @+ = @a " Copy register 'a' to clipboard
:let @/ = "search" " Set search register
" APPEND TO REGISTER (programmatically)
:let @A = "\nnew line" " Append to register 'a'
:let @a .= " more" " Append inline
" PASTE REGISTER IN INSERT MODE
Ctrl+R a " Insert register 'a'
Ctrl+R + " Insert clipboard
Ctrl+R = " Insert expression result
Ctrl+R / " Insert last search
Ctrl+R : " Insert last command
Ctrl+R % " Insert filename
" PASTE LITERALLY (no autoindent issues)
Ctrl+R Ctrl+R a " Literal insert, no interpretation
Ctrl+R Ctrl+O a " Literal, no autoindent
Infrastructure Editing Patterns
" COLLECT IPs FROM CONFIG FILE
:g/\d\+\.\d\+\.\d\+\.\d\+/yank A
"ap " Paste all IPs
" BUILD COMMAND FROM HOSTNAMES
"ayy " Yank first hostname
:s/^/ssh / " Prepend ssh command
"Ayy " Append to register
" Result: register a has all ssh commands
" COPY VAULT TOKEN TO CLIPBOARD (secure)
/VAULT_TOKEN
yi" " Yank inside quotes
"+y " Copy to clipboard
"_yy " Yank line to black hole (clear default)
" TEMPLATE EXPANSION
" 1. Yank template value
/\${.*}
yi$ " Yank placeholder
" 2. Store replacement in named register
"byiw " Yank replacement word
" 3. Replace all occurrences
:%s/\V<Ctrl+R>a/<Ctrl+R>b/g " Replace using registers
" EXTRACT YAML VALUES
:g/key:/yank A " Collect all key definitions
"ap " Review collected values
:%s/^.*: //g " Strip keys, keep values
" BATCH INSERT (config block)
" 1. Build the block in a register
:let @a = " - name: vault-01\n ip: 10.50.1.60\n"
"ap " Paste the block
Advanced Register Techniques
" REGISTER AS MACRO STORAGE
" Registers a-z also store macros!
qa " Record to 'a'
...commands...
q " Stop recording
@a " Playback
"ap " Paste macro as text (to edit!)
"add " Yank edited text back to register
" EDIT A MACRO
:let @a = substitute(@a, 'old', 'new', 'g') " Search/replace in macro
:let @a = @a . "A;\<Esc>j" " Append to macro
" RECURSIVE MACRO
" Register can call itself
qa " Start recording
...commands...
@a " Call self (will repeat until error)
q " Stop recording
" COMBINE REGISTERS
:let @a = @b . @c " Concatenate registers
:let @+ = @a . "\n" . @b " Build clipboard content
" SCRIPT REGISTER OPERATIONS
function! CopyToClipboard()
let @+ = @a
echo "Copied register 'a' to clipboard"
endfunction
" CONDITIONAL PASTE (check if empty)
:exe (@a != '' ? 'normal! "ap' : 'echo "Register empty"')
" PRESERVE REGISTERS (for functions)
let save_a = @a
...use register a...
let @a = save_a
Register Gotchas
" WRONG: Delete then paste (lost original yank!)
yiw " Yank word
diw " Delete word → OVERWRITES default register!
p " Pastes deleted word, not yanked!
" CORRECT: Use yank register
yiw " Yank word
diw " Delete word
"0p " Paste from YANK register (preserved!)
" WRONG: Pasting multiple times after delete
yy " Yank line
dd " Delete line
p " Pastes deleted line
p " Still pasting deleted line...
" CORRECT: Use named or yank register
"ayy " Yank to named register
dd " Delete line
"ap " Always get yanked line
" WRONG: Uppercase for single yank (appends!)
"Ayy " APPENDS to register a!
" CORRECT: Lowercase for replace, uppercase for append
"ayy " REPLACE register a
"Ayy " APPEND to register a
" WRONG: Expecting numbered registers for small deletes
x " Goes to "-, not "1
" CORRECT: Small deletes use "- register
x " Delete char → "-
dw " Delete word (less than line) → "-
dd " Delete line → "1
" WRONG: Search register in substitute
:%s/@//new/g " Literal "@/"
" CORRECT: Reference search register
:%s/\V<Ctrl+R>//new/g " Uses actual search pattern
Black Hole Register Fundamentals
" THE BLACK HOLE REGISTER ("_)
" Discards text - nothing goes to any register
" Essential for replacement workflows
" BASIC USAGE
"_dd " Delete line → nowhere
"_d$ " Delete to EOL → nowhere
"_dw " Delete word → nowhere
"_x " Delete char → nowhere
"_D " Delete to EOL → nowhere
" CHANGE OPERATIONS (most common use)
"_cw " Change word → discards old
"_ciw " Change inner word → discards old
"_ci" " Change inside quotes → discards old
"_ci) " Change inside parens → discards old
"_ct, " Change until comma → discards old
"_c$ " Change to EOL → discards old
"_C " Same as "_c$
"_cc " Change line → discards old
" WHY USE BLACK HOLE?
" Default register holds last yank OR delete
" Without blackhole: yank → delete → paste = deleted text (not yanked!)
" With blackhole: yank → "_delete → paste = yanked text (preserved!)
The Replace Pattern
" STANDARD REPLACE WORKFLOW
" Goal: Replace target text with yanked text, multiple times
" Step 1: Yank replacement text
yiw " Yank inner word
" Step 2: Find target
/target
" Step 3: Replace using black hole
"_ciw<Ctrl+R>0<Esc> " Change word, paste yank register
" Breaking it down:
"_ " Black hole (discard old text)
ciw " Change inner word (enters insert mode)
<Ctrl+R>0 " Insert yank register content
<Esc> " Return to normal mode
" REPEAT PATTERN
" After first replace:
n " Find next target
. " Repeat last change (the whole "_ciw...)
" ALTERNATIVE: Visual mode paste
" Also preserves yank register
viw " Visual select word
"0p " Paste from yank register (visual replaces)
Text Object Combinations
" BLACK HOLE + TEXT OBJECTS = Power moves
" WORDS
"_diw " Delete inner word
"_daw " Delete word with space
"_ciw " Change inner word
"_caw " Change word with space
" SENTENCES/PARAGRAPHS
"_dis " Delete inner sentence
"_dip " Delete inner paragraph
"_cis " Change inner sentence
"_cap " Change paragraph with blank lines
" QUOTED STRINGS
"_di" " Delete inside double quotes
"_da" " Delete including quotes
"_ci' " Change inside single quotes
"_ca` " Change including backticks
" BRACKETS/PARENS/BRACES
"_di) " Delete inside parentheses
"_da] " Delete including brackets
"_ci} " Change inside braces
"_ca> " Change including angle brackets
" TAGS (HTML/XML)
"_dit " Delete inside tag content
"_dat " Delete including tags
"_cit " Change inside tag
"_cat " Change including tags
" BLOCKS (code blocks)
"_dib " Delete inside block (parens)
"_daB " Delete including block (braces)
"_ciB " Change inside braces block
Motion Combinations
" BLACK HOLE + MOTIONS
" LINE OPERATIONS
"_dd " Delete line
"_D " Delete to end of line
"_d0 " Delete to start of line
"_d^ " Delete to first non-blank
" WORD MOTIONS
"_dw " Delete to next word
"_dW " Delete to next WORD
"_db " Delete to previous word
"_de " Delete to end of word
" SEARCH MOTIONS
"_d/pattern " Delete up to pattern
"_d?pattern " Delete back to pattern
"_dn " Delete to next search match
"_dN " Delete to previous match
" CHARACTER MOTIONS
"_df, " Delete through comma (inclusive)
"_dt, " Delete until comma (exclusive)
"_dF( " Delete back through paren
"_dT( " Delete back until paren
" LINE NUMBER MOTIONS
"_d10G " Delete to line 10
"_d} " Delete to end of paragraph
"_d{ " Delete to start of paragraph
"_dgg " Delete to start of file
"_dG " Delete to end of file
Infrastructure Editing Workflows
" REPLACE IP ADDRESS (preserve yank)
" 1. Yank new IP first
/10\.50\.1\.60
yiW " Yank IP (including dots)
" 2. Find old IP and replace
/10\.50\.1\.50
"_ciW<Ctrl+R>0<Esc> " Replace, preserving new IP
" 3. Repeat for all occurrences
n.n.n. " Find next, repeat change
" REPLACE HOSTNAME IN SSH CONFIG
" Before: Host old-server
" HostName old-server.example.com
" After: Host new-server
" HostName new-server.example.com
" 1. Yank new hostname
/new-server
yiw
" 2. Replace in Host line
/Host old
"_ciw<Ctrl+R>0<Esc>
" 3. Replace in HostName line
/HostName old
"_ciw<Ctrl+R>0<Esc>
" UPDATE CONFIG VALUE (preserve original)
" YAML: server: old-value
" Goal: Replace old-value with yanked new-value
" 1. Yank replacement
/new-value
yiw
" 2. Go to target line
/server:
f: " Find colon
w " Move to value
"_ciw<Ctrl+R>0<Esc> " Replace value
" CLEAN SENSITIVE DATA FROM LOGS
" Goal: Remove tokens but keep structure
/token:
f:w " Move to token value
"_ciw[REDACTED]<Esc> " Replace with placeholder
Macros with Black Hole
" MACRO: Replace all matches while preserving yank
" 1. Yank replacement text first
yiw
" 2. Record macro
qa
n " Find next match
"_ciw<Ctrl+R>0<Esc> " Black hole change, paste yank
q
" 3. Execute macro repeatedly
100@a " Run until no more matches
" MACRO: Clean up multiple config values
" Pattern: Replace each "TODO" with proper value
" 1. Yank the correct value
/correct_value
yiw
" 2. Record cleanup macro
qa
/TODO<CR> " Find TODO
"_ciw<Ctrl+R>0<Esc> " Replace with value
q
" 3. Run on all occurrences
:g/TODO/normal @a
" MACRO: Update hostnames in inventory
" Pattern: old-host-01 → new-host-01, etc.
" Record with black hole to preserve clipboard
qa
/old-host
"_cwn new-host<Esc> " Black hole the old prefix
n " Move to next
q
@@ " Repeat
Visual Mode Alternative
" VISUAL MODE PASTE = implicit black hole!
" When pasting in visual mode, selected text is discarded automatically
" STANDARD PATTERN
viw " Visual select word
"0p " Paste from yank register
" The visually selected text goes to default register
" But yank register "0 is preserved!
" REPEAT WORKFLOW
yiw " Yank replacement word
/target
viw"0p " Visual replace
n. " Find next, repeat
" BLOCK VISUAL FOR COLUMNS
" Replace column values
<Ctrl+V>jjj " Block select column
"0p " Replace all with yanked
" VISUAL LINE REPLACE
yy " Yank line
/pattern
V"0p " Visual line replace
" COMPARISON: Black hole vs Visual paste
" Black hole: "_ciw<Ctrl+R>0<Esc> (5 key sequence)
" Visual: viw"0p (5 key sequence)
" Both work! Choose based on preference
Black Hole Gotchas
" WRONG: Forgetting black hole breaks workflow
yiw " Yank word
ciwreplacement<Esc> " Change word (overwrites register!)
n " Find next target
. " Repeats change, but...
" Pastes "replacement" not original yank!
" CORRECT: Always use black hole for preserve workflow
yiw " Yank word
"_ciwreplacement<Esc> " Black hole change
n. " Find next, repeat (still have original)
" WRONG: Using normal register then black hole
dd " Delete line (goes to "1)
"_dd " Black hole delete
u " Undo black hole delete
p " Paste... but "1 still has first delete
" CORRECT: Understand register behavior
" Black hole only affects THAT operation
" Previous register contents remain
" WRONG: Expecting black hole in all modes
" Black hole works in normal mode, not insert!
i<Ctrl+R>_ " ERROR: Can't insert from black hole
" WRONG: Using black hole when you want history
"_dd " Delete line
u " Undo
p " Can't paste - it's gone!
" CORRECT: Use normal delete if you might need it
dd " Delete (can recover from "1)
Quick Reference
" ESSENTIAL BLACK HOLE COMMANDS
"_dd " Delete line (preserve registers)
"_ciw " Change word (for replace workflow)
"_ci" " Change inside quotes
"_d$ " Delete to EOL
" REPLACE WORKFLOW (memorize this)
yiw " 1. Yank replacement
/target<CR> " 2. Find target
"_ciw<Ctrl+R>0<Esc> " 3. Replace (preserves yank)
n. " 4. Repeat
" ALTERNATIVE VISUAL WORKFLOW
yiw " 1. Yank replacement
/target<CR> " 2. Find target
viw"0p " 3. Visual replace
n. " 4. Repeat
" PLUGIN SUGGESTION: vim-cutlass
" Makes all delete operations use black hole by default
" Then use 'x' for cut (like normal editors)
" Plug 'svermeulen/vim-cutlass'