command mode history

use q: to access previously ran commands in command mode (:)

if you're already in command mode then you can do the same with <C-f>. This one is especially handy if you already have part of the command written out since using <C-f> will allow you to edit the in-progress command further but in a separate buffer with all other modes at your disposal.

This allows you to search and edit previously ran (or even the current, in-progress command). Press enter to execute the command under the cursor.

You can exit this mode without any effect by hitting enter on an empty entry (q: will start on an empty entry).

edit previously committed files

print a list of files that were modified in a given commit (from git log or from GitHub)

:read !git show --pretty="format:" --name-only <commit-hash>

or for the files modified in the latest commit

:read !git show --pretty="format:" --name-only HEAD

and then use gf to open those files.

It was useful when I needed to ssh into a machine and open the same files that I had last modified in the commit to make further changes.

easy mode

vim has an easy mode. You enable it by using the -y (vim -y). It makes vim behave like a regular "click-and-type" text editor. In this mode, regular shortcuts work as expected, ctrl + s for save, ctrl + c for copy, ctrl + v paste, ctrl + z to undo, ctrl + y redo.

The downside (and the reason nobody makes a big deal about it) is that is was designed to be used inside a GUI, so there is no shortcut to quit. You need to close whatever graphical interface vim is in.

Not all is lost, I think it provides a nice base to use vim for quick edits. For the people who will never use vim on purpose, I will recommend creating a .vimrc on their home folder with this content.

" Enable 'easy mode'
source $VIMRUNTIME/evim.vim

"  Ctrl + q to Quit vim
inoremap <c-q> <c-o>:q<cr>

This will create a ctrl + q shortcut to quit. You could also replace (or add) <Esc> as a shortcut to quit.

This way even if you enter vim by accident it will behave somewhat like a "normal" text editor.


easy text replacement

You can * in a word, and then :%s//replacement will replace that word for replacement.

The empty string in s// tells vim to use the string in the / register.

apply a macro only to a set of lines

Use the normal command in Ex mode to execute the macro on multiple/all lines:

Execute the macro stored in register a on lines 5 through 10.

:5,10norm! @a

Execute the macro stored in register a on lines 5 through the end of the file.

:5,$norm! @a

Execute the macro stored in register a on all lines.

:%norm! @a

Execute the macro store in register a on all lines matching pattern.

:g/pattern/norm! @a

To execute the macro on visually selected lines, press V and the j or k until the desired region is selected. Then type :norm! @a and observe that the following input line is shown.

:'<,'>norm! @a

Enter :help normal in vim to read more.


navigating the changelist

g; takes you backward one step in the 'changelist'. You can keep g;-ing to go to your last edit, the one before that, the one before that, and so on, and you can use g, to come back forward in the change list. This is similar to how ; and , work with f, F, t, and T.

Also, if you know that you want to go right into insert mode in the place where you last edited (technically, where you last stopped insert mode), you can do gi

navigate file by blank lines

Use { and } to jump through file by blank lines.

bulk, confirmed text replacement

This was handy for bulk, confirmed renaming, I used telescope's live_grep feature to put the results in a quickfix list (although any other method for populating a quickfix list would work) and then ran:

:cfdo %s/find/replace/gce | %s/findanother/replaceanother/gce | %s/findyetanother/replaceyetanother/gce | update

to do multiple replacements on the files in the quickfix list and then saved them all with update. I could've saved them all with :cfdo w as well.

replace line with external command output

use !! in normal mode to replace line with output of an external command

debugging syntax highlighting

All useful for debugging syntax highlighting and what is applying it:

:setlocal syntax?
:syntax list
:verbose set ft?

switch buffers without a plugin

One way to switch buffers without using any plugin is to use:


One keymap that you can use:

nnoremap <Leader>b :buffer<Space>

Then you can press TAB and select the buffer you want to go into


print current position of cursor

g Ctrl-G (normal mode) - prints the current position of the cursor in five ways: Column, Line, Word, Character and Byte

reddit tip dump

NOTE A lot of these are duplicates of tips already discovered/shared but figured I'd dump them all here anyway.

All of the following come from this reddit thread. It might be worth checking out again as there might be more that trickle in there.

The . key actually has a special behavior with the number registers ”0 To ”9. Specifically, if the change that the . command is repeating references a number register, the . command will actually increment the referenced register after running. This is a little hard to explain, but try doing this:

  1. ”1p
  2. u.

Repeat u. as many times as you’d like.

This will cycle through the number registers, starting with register 1, putting it, then undoing it, then putting register 2, undoing it, etc.

Why is this useful? The number registers contain your last deletes! If you want to recover some accidentally deleted text, you can repeat the steps above until you get the text you want.

g<C-a> - in visual mode invokes <C-a> command for every line n times, where n is number of line in visual selection. Very useful for creating numbered lists: Create 10 lines with 0. at the beginning 10o0.<esc> Select paragraph vip Use g<C-a>. You get list from 1 to 10.

Vim has many marks & lists that it stores positions automatically.

Marks: '< & '> start/end of visual selection

'[ & '] - start/end of last change or yank

'. - position of where last change was made

'^ - position of cursor when last Vim last left insert mode - This is how gi command works

'' - position before last jump (Super useful!). See :h ''

Use g;/g, to move through the changelist positions (I use this all the time)

<c-o>/<c-i> to move through the jumplist

:visual o/O … flip selection “caret”

gv … reselect previous visual selection

/foo/e … end of search rather than beginning. Also see :help search-offset

// … “search for the last search” (eg: :%s//XXX/g … replace last search with XXX)

g/foo/norm A,<esc>0fxietc…etc…like a macro<cr>

…basically there are a few ways to invoke :norm … which lets you kind of “just do what you want” on matching lines. With the search-offset functionality mentioned above, you can do some wizardly efficient editing.

<C-w><C-r> = rotate splits

The & command in normal mode repeats the last ":s/" command (without flags) on the current line. There's also g& which does the substitute (using the most recent search) on every line with the same flags. They seemed like dumb niche things, but I found myself using them remarkably regularly.

:help & :help g&

A "range" (:help :range) for an Ex command can accept all sorts of modifying ranges like /pattern/- to refer to the line before the next "pattern" or ?pattern?+3 to refer to 3 lines after the previous "pattern". And they can chain such as ?pattern1?/pattern2/-2 to search backwards for "pattern1" and then search forward for "pattern1" and then move back two lines. These can also include marks (e.g. "<+2 refers to two lines after the beginning of the most recent selection)

The {cmd} that follows a :g command can take a range relative to the match:

:{range1}g/{regex}/{relative_range}{cmd} Want to delete every paragraph containing the word "carrot"?

:g/carrot/'{+,'}d Want to indent 3 lines after each "carrot" to one line before the following "pepper"?

:g/carrot/+3;/pepper/- > I use this one all the time and love it :-)

Related to the :g command, here’s another one that people often miss — you can chain :g and :v commands.

For example, :g/foo/g/bar/d deletes every line matching both foo and bar. :g/foo/v/bar deletes every line that matches foo but not bar. The great thing is, you can chain this as many times as you want!

I have used this in the past to delete all functions that don’t contain the word foo, for instance. Something like :g/^func/v/foo/norm!V$%d.

ciw + ctl-r 0 - This makes the paste repeatable by not yanking the pasted over text.

native fuzzy search

fuzzy search in vim with .\{-} in between search terms

split lines by text width

Split lines with gq

  • In visual mode, it will split whatever is selected.
  • In normal mode, you follow gq with a motion.

For example, gql will split one line to the currently set width. To set the width of the split lines to be different from your current setting, you can use

:set textwidth=<n>

Where n=number of characters you want in a line, e.g., 10, and change back to your normal width when you're done.

git diff and merge tool

If I ever used something for my merge/diff tool for git I would use either meld or diff-so-fancy but doing it in vim seems awesome as well:

Vim can be used as a mergetool to handle git merge conflict.

First, setup Vim as a mergetool in your gitconfig. Then, during a merge conflict, run:

git mergetool

You can then use Vim to pick which change(s) to apply to the working copy.


To setup Vim as a mergetool in my gitconfig, I added these in my ~/.gitconfig (your gitconfig may be in a different location):

  editor = vim
  tool = vimdiff
  conflictstyle = diff3
  prompt = false

Useful commands.

To get changes from local/base/remote:

  • :diffget LOCAL
  • :diffget BASE
  • :diffget REMOTE

To go to next/prev changes:

  • ]c
  • [c

show whitespace characters

To show whitespace characters use:

set list (set nolist to hide it)

To determine which characters show up as whitespace (since the defaults suck) you can set them with this:

set showbreak=↪
set listchars=eol:¬,tab:>·,trail:~,extends:>,precedes:<,space:␣

paste in fzf.vim prompt

Figured out a solution to that paste in fzf thing btw. So it turns out that fzf just runs in a terminal popup so it's the same keybindings for the :term mode. So you can paste the current clipboard the manual way with <C-w>"+ or map that to a keybind using tnoremap <custom-binding-here> <C-w>"+.

delete without yanking

" delete without yanking
nnoremap <leader>d "_d
vnoremap <leader>d "_d

" replace currently selected text with default register without yanking it
vnoremap <leader>p "_dP

_ is the "blackhole register"

show/debug key mappings

Use :verbose map to show where key mapping(s) are defined (see :help map-verbose). There are other variants as well that can be used with or without verbose:

:nmap for normal mode mappings :vmap for visual mode mappings :imap for insert mode mappings

To output the shortcuts, with where they were defined, to a text file do:

:redir! > vim_keys.txt
:silent verbose map
:redir END

opening files

open a file to a specific line number:

vim +n where n is the line number (+92 will open the file on line 92)

open a list of files:

vim file1 file2 file3

You can also use -o and -O for splits and vertical splits, respectively. -p for tabs.

sort by elements in a list

If you want to sort lines based on the second element on the list:

pancake, donut, waffle
sushi, pasta, taco
apple, banana, carrot
water, apple juice, milk

Run: :sort /,/

Vim will use the characters after the match to sort.

water, apple juice, milk
apple, banana, carrot
pancake, donut, waffle
sushi, pasta, taco

insert special characters

Use ctrl-k + 2 letters to add special characters. Examples:

  • oo • bullet
  • Db ◆ diamond bullet
  • Pd £ pound
  • Eu € euro
  • -N – en dash
  • -M — em

Read more and see the source

the move command

Vim has a :move (:m) command.

To move line 2 to line 8, run :2m8

:14,17m$ this moves lines 14-17 to the end of the file.

:3m. this moves line 3 to the current line.

percentage navigation of file

{count}% (in normal mode) will take you to that percentage of the file length.

other ways to save files

:x (as well as ZZ) is like :wq, but writes only when changes have been made.

navigate wrapped lines

Navigate up and down on a wrapped line with gj and gk. Go the beginning and end of a wrapped line with g^ and g$. Use gm to go the middle of a wrapped section (gM to go the middle of the whole, wrapped line).

appending text

A to append to end of line.

Use $A in visual block mode to append to the end of each line regardless of different line lengths.

This can also be done by pressing : while in visual block mode with the resulting command like the following:


learn vimscript

Learn vimscript the hard way

duplicating files

This is something I would always leverage a file tree plugin for. I can't find a good way to accomplish this with my current file tree plugin (NvimTree) so finding a native, effective way without plugins was needed.

Method 1: You can open the new file first and then copy the original file into the buffer

:e another-file
:r original-file

Method 2 (my personal favorite): use :sav duplicated-file while in the file you want to duplicate.

:sav[eas][!] [++opt] {file}
            Save the current buffer under the name {file} and set
            the filename of the current buffer to {file}.  The
            previous name is used for the alternate file name.

working with delimiters

Use c% to change text within delimiters. Example:

link_to("text", my_path(singularize("one"), pluralize(double("two"))))
                ^      A                                            B

"It also handles [] square brackets, {} curly braces and some other things. It can be used as a standalone motion or with other operators than c.

For example, you could use %d% to change remove_my_argument(BigDecimal(123)) into remove_my_argument."


sorting lines

You can sort lines with Vim's sort() command. To sort the entire buffer, simply run:


To sort starting from line 6 to the end of the file, run: :6,$sort

You can also sort just the lines that are visually selected.

swap between last 2 buffers

Ctrl + ^ to swap between last 2 buffers.

useful text objects in vim

Useful text objects in vim

editing macros

If you need to edit a macro (because you forgot to remember to add a motion key for the macro to be effectively repeatable):

  1. :let @q=" open the q register
  2. <C-r><C-r>q paste the contents of the q register into the buffer
  3. ^ add the missing motion to return to the front of the line
  4. " add a closing quote
  5. finish editing the macro

An alternate way of doing this is:

  1. "qp paste the contents of the register to the current cursor position
  2. I enter insert mode at the beginning of the pasted line
  3. ^" add the missing motion to return to the front of the line and add a quote
  4. return to normal mode
  5. "qyy yank this new modified macro back into the q register
  6. dd delete the pasted register from the file your editing

(Use ctrl+v <key> to get the actual character key for escape sequences for macros and whatever else)

go to last insert

gi to go to the last place you were in insert mode.

diff command output

vimdiff <(ls) <(ls ~/otherDir)

Compare the output of two commands using vimdiff and bash "process substitution"

open source file in remote vcs (fugitive)

Some of you problably know this. One of the most used commands I use inside Vim is :GBrowse (comes with fugitive). This command opens the local file in GitHub for you. This comes very handy if you want to share the link with others.


repeat last search

// (normal mode) to repeat last search

repeat substitute command

You can repeat the last substitute command with &. If you just ran :s/one/two/, pressing & will execute :s/one/two/ again.

Alternatively, you can also run :s to repeat the last substitute command.


relative copy and paste

Relative copy and paste in vim:


:t is an alias for :co[py] and can be used in command mode like so


This will copy 12 lines above the cursor and paste on the current line it also works with different destinations (:-12t+19<cr>) and ranges

:3t9 - copy line 3 to line 9. Reads 3 to 9.

:3t. - copy line 3 to the current line.

different histories

Vim has 5 different histories. Here's how you can see each of them:

:his c    - cmd-line history
:his s    - search history
:his e    - expression history
:his i    - input history
:his d    - debug history


persistent folds

Save and restore folds automatically:

augroup AutoSaveFolds
  autocmd BufWinLeave * mkview
  autocmd BufWinEnter * silent loadview
augroup END

Defeult value for viewdir is ~/.vim/views on Unix

travel through undo history

Time travel in through your Vim undo history:

:earlier 2h
:later 15m
:earlier 30s

gn and cgn

gn searches forward and visually highlights the last search pattern.

If you had searched for "foo" (/foo), you can run cgnbar to change the next "foo" and replace it with "bar".

This works great with the dot command. You can now just run ..., instead of n.n.n.


another way to exit insert mode

Along with the typical <esc> or <c-[>, you can also exit insert mode using <c-c> (Ctrl + c).

find and replace with multiple regular expressions

Limit a search and replace operation between lines matching 2 regex patterns using /pattern1/,/pattern2/s/search/replace/

display all lines containing word

Did you know that you can display all lines containing the word under cursor with [I


repeat last command

The last command entered with : can be repeated with @: and further repeats can be done with @@.

Super handy when going through all the matches in an :Ack search for example.

So when going through the quickfix list (what Ack displays results in) then instead of typing :cn to go through each entry in the list you can just do @@ after :@'ing once.

vim's built in user guide

Vim's built-in user guide;

:h usr_toc.txt

open file to first pattern match

You can open a file with vim to the first match of a pattern like so:

vim file.txt  +/<pattern>

fix issues with delays

In case there is any issue with delays when pressing escape or just keypresses in general. I remember experiencing this in the past and would be good to have it documented:

vi escape delays


vim: set timeoutlen=1000 ttimeoutlen=0


tmux: set -s escape-time 0

reselecting text

You can quickly reselect the last visual mode area selection with gv

I have this in my vimrc as well:

" Select text that was last pasted
nnoremap gp `[v`]

undo tree files

To save your undo trees in a separate file, use :wundo and :rundo.


After editing hello.txt, I can save my undo tree with

:wundo! hello.undo

Close vim. Open hello.txt. We can't undo. This is normal. Now read undo file:

:rundo hello.undo

You can undo now.


visual mode highlighting

In visual mode, if you need to highlight text in the reverse direction, you can hit o to toggle which end to highlight from.

insert with count prefix

Insert command accepts a count.

10iHello Vim!

This will give you "Hello Vim!" repeated 10x!

Works with all insert mode commands (i, I, a, A, o, O, gi, gI)

vim registers (article)

This article is great

closing tabs and buffers

:windo bd will delete all buffers in the current tab. :tabclose closes the tab but does not delete the buffers.

folding with regular expressions (article)

parent level parens

Put a count before a <action>i( to go at a parent level of parentheses.

current file paths

In insert mode, type <C-r>% to insert the name of the current file.

In command mode (after typing a colon), type <C-r>% to insert the name of the current file. The inserted name can then be edited to create a similar name.

In normal mode, type "%p to put the name of the current file after the cursor (or "%P to insert the name before the cursor).

1ctrl+g - print the full file path of a file in vim.

Plain ctrl+g will do the relative path, 1 will do full path, 2 will do full path and buffer number.

Some handy keymaps:

" Copy relative file path to system clipboard
nnoremap <leader>cf :let @+=expand("%")<CR>
" Copy absolute file path to system clipboard
nnoremap <leader>cF :let @+=expand("%:p")<CR>
" Copy file name to system clipboard
nnoremap <leader>ct :let @+=expand("%:t")<CR>
" Copy directory name to system clipboard
nnoremap <leader>ch :let @+=expand("%:p:h")<CR>

vim lists article

Found this for vim fold keybinds

quickfix list commands

Run the command to each line of the quickfix list:

:Ack pattern
:cdo s/pattern/newpattern/g

Note: cdo is for executing a command on each entry in the quickfix list, cfdo is for executing a command for each file in the quickfix list.

character casing

I always used ~ to invert the case but there are upper and lower functions with gU (upper) gu (lower) gUU (uppercase current line) guu (lowercase current line). gUw to uppercase a word.

fold keybinds

Found this for vim fold keybinds

delete matching patterns

Delete all lines not matching a pattern:


In this example, all lines not containing these numbers will be deleted.

a guide to splits

vim splits a guide to doing exactly what you want

Some things to consider adding to my vimrc per that post:

" window
nmap <leader>swl :topleft  vnew<CR>
nmap <leader>swh :botright vnew<CR>
nmap <leader>swk :topleft  new<CR>
nmap <leader>swj :botright new<CR>
" buffer
nmap <leader>sl :leftabove  vnew<CR>
nmap <leader>sh :rightbelow vnew<CR>
nmap <leader>sk :leftabove  new<CR>
nmap <leader>sj :rightbelow new<CR>

jumplist navigation

Use <c-o> to go to previous spot in the 'jumplist' and <c-i> to go forward.


When you are displaying more than one buffer in the same window, you can set the scrollbind option in each buffer so they scroll together.

In each buffer that should scroll simultaneously, enter the command:

:set scrollbind

You can enter scb as an abbreviation for scrollbind, and the ! flag causes :set to toggle a boolean option. Therefore, it is convenient to enter the following to toggle scrollbind on or off:

:set scb!

use the :diffthis command to initiate a diff when Vim is already running.

e.g. file is open, open new file in split screen, invoke diff mode in both splits with :diffthis and turn it off with :diffoff.

cursor and view movement

shift + h - move cursor to top line
shift + l - move cursor to bottom line
shift + m - move cursor to middle line

zt - shift view so cursor is on the top line
zz - shift view so cursor is on the middle line
zb - shift view so cursor is on the bottom line

C-y and C-e to scroll the viewport up and down line by line, keeping the cursor in the same position (similar behavior to zt, zz, zb)

select/move between functions

va}V (within the declaration) or $V% (same line as declaration) to select the whole function including the function declaration

]] and [[ to move between function declarations

replace multiple characters

Use R to replace multiple characters

incrementing sequences

Use g ^a for making incrementing sequences


persistent undo

Save your undo history. Useful for opening up a file and being able to keep undos from a previous editing session or even upload the undo file to a server with the same exact contents and be able to undo on that file as well.

:help undo-persistence

Persistent Undo in Vim - Jovica Ilic

lynx output in vim

Install lynx then go into vim and try this out:

read !lynx --dump

insert normal mode

While in insert mode, if you type Ctrl-o, you'll be in "Insert-Normal-mode"

Examples (while in Insert-Normal-mode):

Ctrl-o zz    " center your position while typing
Ctrl-o dfx   " delete to 'x'

file encryption

vim -x filename will prompt for an encryption key

Also, if you are already editing a file, you can just run :X to set an encryption key to be used once the file is saved.

g command comments


will comment out lines containing _pattern_ (if # is your comment character)

Another way of doing this is with normal commands instead of text substitution:

:%g/912150\|912147\|912145\|912157\|912155\|912151/norm I// 

Note: there is a trailing space in this code block

swap g with v at the beginning and it will comment out lines that don't match the pattern.

hacker news links

Get all the links from hacker news in vim:

:read !curl

insert calculation result

While in insert mode, run <C-r>=60*60<Enter> to get the result of the calculation inserted at the cursor.

Super nice for calculating the time of something in millis or something without having to have the program do the calculation every time.

last modified position

'. jumps to the last modified line

`. jumps to the last position within the modified line

find duplicate lines

simple way to find duplicate lines in vim:

  1. Sort the file using :sort
  2. Execute command :g/^\(.*\)$\n\1$/p


Stolen from this site. Definitely worth a full read.

<C-d> and <C-t> indent back and forward in insert mode

The normal mode equivalent is >> and <<

I typically use == for auto indentation but this comes in handy when you want to be explicit or there isn't any autoindentation

Using the detectindent plugin, indentation is automatically detect indent based on what is already in the file (expandtab, shiftwidth, tabstop settings)

:autocmd BufReadPost * :DetectIndent

modal cursor and color changes

" change cursor to block/ibeam when in normal/insert mode
if &term == 'xterm-256color' || &term == 'screen-256color'
    let &t_SI = "\<Esc>[5 q"
    let &t_EI = "\<Esc>[1 q"

Also came across this snippet for changing cursor colors depending on modes:

if &term =~ "xterm\\|rxvt"
  " use an orange cursor in insert mode
  let &t_SI = "\<Esc>]12;orange\x7"
  " use a red cursor otherwise
  let &t_EI = "\<Esc>]12;red\x7"
  silent !echo -ne "\033]12;red\007"
  " reset cursor when vim exits
  autocmd VimLeave * silent !echo -ne "\033]112\007"
  " use \003]12;gray\007 for gnome-terminal and rxvt up to version 9.21

case search

Add set ic (set ignorecase) to your vimrc to have search ignore case by default.

Use case sensitive search only if a capital letter is used in the search set smartcase

Set them in the editor temporarily in command mode: :set ic or :set smartcase

To turn them off use :set noic or :set nosmartcase

Toggling the settings could be useful as well with :set ic! and query its value with set ic?

insert contents of a file

You can insert the contents of a file into your current working file with:

:r filename.txt

That will place the contents of filename.txt at your cursors location.

you don't need multiple cursors in vim

You don't need multiple cursors in vim

Some notable links from that article:

how to edit an existing vim macro

En Masse - a vim plugin to edit every line in a quickfix list at the same time.

And this one as well Why Vim Doesn't Need Multiple Cursors

open files in file contents

To open the filename under your cursor type gf in normal mode. <C-W>f opens in a split, and <C-W>gf opens in a new tab.

cheatsheet image

Cheat sheet as a picture

shared system clipboard

Use the system clipboard for both copying and pasting with normal yy and such

set clipboard=unnamedplus

u and U (undo)

u undoes the last change in vim

U returns the current line to its original state