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'