Vim - The Mighty Text Editor that lets you edit text at the speed of thought
Getting Started With Vim
Basic Vim Motions
-
hjkl
- left, up, down, right -
0
- beginning of line -
^
- beginning of text (within a line) -
$
- end of line -
gg
- beginning of file -
H
- top of the visible text within the window -
M
- middle of the visible text within the window -
L
- bottom of the visible text within the window -
G
- end of file -
w
- move to the beginning of the next word -
e
- move to the end of the next word -
t<char>
- move before the next appearance of character<char>
in this line (from left to right) -
T<char>
- like above but the previous appearance (from right to left) -
f<char>
- move to the next appearance of character<char>
in this line (from left to right) -
F<char>
- like above but the previous appearance (from right to left)
Basic Vim Commands
-
i
- go into insert mode before the current character -
I
- go into insert mode at the beginning of the line (shortcut for^i
) -
a
- go into insert mode after current character -
A
- go into insert mode at the end of the line (shorcut for$a
) -
c
- change (delete and insert) -
cw
- change (delete and insert) word -
cc
- change line -
C
- change everything till the end of the line (shorcut forc$
) -
s
- change a letter (shorcut forcl
) -
S
- change complete line (_shortcut for^c
) -
x
- delete a character -
dw
- delete word -
dd
- delete line -
gu
- change to lowercase -
gU
- change to uppercase -
guw
- change word to lowercase -
guu
- change line to lowercase -
.
- repeat last change -
>
and<
- indent/unindent -
>>
- Increase indentation in current line -
<<
- Decrease indentation in current line -
>G
- Increase indendation till the end of the file -
=
- fix indentation -
o
- new line and insert mode (shortcut forA<ENTER>
orA<CR>
) -
O
- new line above and insert mode (shortcut forko
)
Undo and Redo
Normal Mode
u
- undo last changeU
- Undo all latest changes on one line, the line where the latest change was made.U
itself also counts as a change, and thusU
undoes a previousU
.C-R
- redo- Check
:help undo
for more info
Insert Mode
These are equivalents to undo (although not exactly) when in insert mode:
CTRL-H
delete character before the cursorCTRL-W
delete word before the cursorCTRL-U
delete all characters before the cursor in the same line
Combining commands (operators) and motions to get things done
These are Vim’s more common commands (:h operator
). They are used to perform operations on text:
c - change
d - delete
y - yank into register (does not change the text)
g - swap case
gu - make lowercase
gU - make uppercase
! - filter through an external program
gq - text formatting
> - shift right
< - shift left
You can combine these operators with motions and counts (:h cursor-motions
) to apply them to specific bits of text.
// motions
w - move to beginning of next word
b - move backwards to beginning of previous word
e - move to end of next word
ge - move backwards to the end of previous word
0 - move to beginning of the line
$ - move to the end of the line
etc...
// text objects
aw - around a word
iw - inside a word
etc...
A complete command will follow a pattern like this:
{operator}{count}{motion}
or
{count}{operator}{motion}
For instance:
dw
- delete a wordcw
- change a wordd2w
- delete 2 wordscta
- change until the next occurrence of the lettera
(non inclusive)
Search
Character Search
f
- find next occurrence of character in current line (mnemonic find)F
- find previous occurrence of character in current linet
- find next occurrence of character in current line and place cursor before it (mnemonic till or until)T
- find previous occurrence of character in current line and place cursor after it;
- repeat lastf
,t
,F
,T
commands,
- repeat lastf
,t
,F
,T
commands in the opposite direction
File Search
/{pattern}<CR>
- search forward for occurence of pattern?{pattern}<CR>
- search backward for occurence of patternn
andN
work with/
and?
as;
and,
above*
- go to next occurrence of pattern under cursor (repeat search)#
- go to previous occurrence of pattern (repeat search)
A common worflow to search stuff in Vim is to use the /{pattern}
motion and press enter immediately after to exist command-line mode and jump back into normal mode in the first match of the pattern. A useful alternative to keep refining a search is to use:
/{pattern}
to search for a pattern- Use
CTRL-G
andCTRL-T
to jump to the next or previous match respectively without leaving the command-line mode
Notice how near the repeating commands are (;
, .
and ,
), and how #
and *
are symmetric and correspond to the middle finger in each hand.
Substitute (replace text with other text)
:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]
Subsitute text with other text:
range
over which to apply the substitutionpattern
to match and substitutestring
to use as replacementflags
likeg
global (substitute all matches within a line)c
to confirm each substitutionn
to ignore substitution and report number of matches:h :s_flags
for more
- replace
count
lines
Some examples:
:%s/foo/bar/g
replacesfoo
forbar
in the whole document%
matches every line in the documentg
applies the substitution to every match within a line
:%s/foo//gn
counts matches offoo
in the whole document:%s/https.*/[&]()/g
replaces urls for markdown links. You can use the&
to inject the matched pattern in the substitution
Repeaters:
&
: repeats last substitution from normal mode (resets flags):s
or:&
: repeats last substitution (resets flags):&&
: repeats last substitution with same flags:%&
: like:&
but for the whole file:%&&
: like:&&
but for the whole file
Global
:g/{pattern}/{command}
- execute ex commandcommand
on lines that matchpattern
:g/foo/d
- delete all lines that havefoo
:g!/foo/d
- delete all lines that don’t havefoo
:v/foo/d
- shorthand for:g!/foo/d
File Navigation
:e#
- go to previous buffer:e#n
- go to buffer numbern
(wheren=1,2,3...
)gf
- go to file (when the cursor is on top of a file)CTRL+O
- go back:buffer
- list buffers
Splits
:split
- create a horizontal split of the current buffer:split {file}
- open file in horizontal split:split +{line}
- open horizontal split in line{line}
:split +
- open horizontal split at the end of the line:split +/{pattern}
- open horizontal split at an specific pattern:vsplit
- like:split
but opens vertical splitsCTRL-W o
- close all other splits (also:only
). There’s a plugin called Zoomwintab.vim that allows you to zoom into a split using the same binding instead of closing all other tabs. This allows you to come back to the original disposition of splits by just using the binding again. It behaves just like tmux zooming but within Vim.
Moving Between Splits
CTRL-W h
- Move to window on the leftCTRL-W j
- Move to window belowCTRL-W k
- Move to window aboveCTRL-W l
- Move to window on the right
Moving splits
CTRL-W H
- Move window to the leftCTRL-W J
- Move window belowCTRL-W K
- Move window aboveCTRL-W L
- Move window to the right
Resizing Splits
:resize -{number}
- decrease window height by{number}
:resize {number}
- increase window height by{number}
:vertical resize -{number}
- decrease window width by{number}
:vertical resize {number}
- increase window width by{number}
[count] CTRL-W -
- decrease window height by one line (or[count]
lines)[count] CTRL-W +
- increase window height by one line (or[count]
lines)[count] CTRL-W <
- decrease window width by one line (or[count]
lines)[count] CTRL-W >
- increase window width by one line (or[count]
lines)[count] CTRL-W =
- make all windows of equal height and width (or[count]
lines)
Visual mode
Visual mode allows you to select bits of text and perform operations on them.
v
- go into character-wise visual modeV
- go into line-wise visual modeC-v
- go into block-wise visual mode
When in visual mode you’ll move one of the ends of the selection while the other one remains fixed. In order to be able to change either end you can type o
to change the current end you’re moving.
Vim And The Command Line Mode
To run a command-line command from Vim use:
$ => execute this in external shell
: => execute this internally in command-line mode
/ => use command-line mode to perform a forward search
? => use command-line mode to perform a backward search
= => use command-line mode to evaluate a Vim script expression
The Vim Way
Vim is optimized for repetition. Take this into account when editing and you’ll be that much efficient:
- Use the
.
command to repeat the last change - Use the
;
,,
,*
,#
commands to repeat motions - Use the
@:
to repeat Ex commands - Use the
&
to repeat substitution (:h :substitute
) - Remove extraneous, unnecessary movement (f.i. use I instead of 0i or A instead of $a)
- Use compound commands that leave you directly in insert mode instead of separate commands (f.i. use
cw
instead ofdwi
orC
instead ofd$i
) - Attempt to make changes repeatable
The dot command (
.
) lets us repeat the last change. It is the most powerful and versatile command in Vim. From Practical Vim
How to Configure and Customize Vim
You normally configure Vim by adding configuration commands inside the .vimrc
file which typically lives in ~/.vimrc
. This file is loaded when you run Vim and is where you want to place information such as the plugins you want to load, color schemes you want to you and custom key bindings that represent the personal way you use Vim.
Customize Vim Key Mappings
Vim lets you define your own key mappings and change existing ones to your heart’s content. This is a powerful way to optimize the way that you write code and be more productive when using Vim.
Vim offers two commands that let you create and modify mappings in different ways: map
and noremap
. You can use map
to map a key sequence to any other key sequence or command:
map tab
The difference between map
and noremap
is that, the first one allows for recursive mappings whilst the second one (noremap - no recursive mappings) doesn’t. A recursive mapping means that Vim will continue scanning the result of a mapping and seeing whether there are other mappings that correspond with this result. A non recursive mapping means that Vim won’t scan the result of these mappings and will use Vim’s default meaning of the result. For instance:
" map E to B, B is recursively mapped to G, go to the end of a file
map E B
noremap B G
" G maps to gg, go to the top of a file
" This mapping doesn't affect the mappings above
" because the second mapping is a no recursive mapping, that is,
" it will not be scanned for more mappings recursively
noremap G gg
This is a list of all mapping commands:
map {lhs} {rhs}
: Maps the key sequence{lhs}
to{rhs}
for the modes where the map command applies. The result, including{rhs}
, is then further scanned for mappings. This allows for nested and recursive use of mappings.noremap {lhs} {rhs}
: As above but it disallows the mapping of{rhs}
, to avoid nested and recursive mappings. Often used to redefine a command.nnoremap {lhs} {rhs}
- same but only normal mode and so on forinoremap
,vnoremap
, etc
unmap {lhs}
: Remove mapping of{lhs}
for the modes where the command appliesmapclear
: Remove ALL mappings for the mode where the map command appliesmap
: List all key mappings for the modes where the map appliesmap {lhs}
: List the key mappings for the key sequence starting with{lhs}
in the modes that apply
Note that you can prepend modes to these commands above to make the command apply to a specific mode. For instance, nmap
applies to normal mode, imap
applies to insert mode and so on.
You can use special characters in mappings with added functionality:
<Plug>
- you may have seen some mapping including<Plug>
.<Plug>
allows plugin authors to make it easier for users of their plugin to map funcionality to new key-bindings. It allows you to temporarily bind<Plug>SomeAction
to an action and then let the user map whichever sequence to that bindingnnoremap wop <Plug>SomeAction
Check out :help key-mapping
for more info.
The Minimal Basic Configuration To Make Vim Play Nicely
I recommend you to take a look at Vim-sensible if you’re using Vim. If you want a better first time experience, then try Vim. Most of the commands from Vim-sensible and those you can find below are set by default if you use NeoVim. You can find more info about NeoVim’s sane defaults at NeoVim.org.
" Color scheme (using a nice built-in dark color scheme)
colorscheme industry
" Filetypes
" This enables file type detection (like filetype on)
" and also loading plugins and indentation per filetype
filetype plugin indent on
syntax enable " enable syntax highlighting
set autoindent " Copy indent from current line when starting a new line
set clipboard+=unnamedplus " use system clipboard
set showcmd " display incomplete commands
set showmode " display the mode you're in
set backspace=indent,eol,start "intuitive backspacing"
set hidden " Handle multiple buffers better
set wildmenu " enhanced command line completion
set wildmode=list:longest " complete files like a shell
""" Search
set ignorecase " case-insensitive search
set smartcase " but case-sensitive if expression contains a capital letter
set relativenumber "show relative line number
set ruler " show cursor position
set incsearch " highlight matches as you type
set hlsearch " highlight matches
set wrap " turn on line wrapping
set scrolloff=3 " show 3 lines of context around cursor
set display+=lastline "Display as much as possible of a window's last line
set title " show terminal title
set visualbell " no beeping
set list " show invisible characters
"" Global tabs/spaces
set smarttab " use spaces instead of tabs
set expandtab " use spaces instead of tabs
set tabstop=2 " global tab width
set shiftwidth=2
set laststatus=2 " Always show a status line
set nobackup " no backups
set nowritebackup " No backups
set noswapfile " No swap files
set autoread " Automatically re-read files changed outside of Vim
set nofoldenable " Disable folding
Here you can find more inspiration for your vimrc:
- Vim-sensible
- Another example of a minimal vimrc
- Vim plugin authors and other Vim users usually have their vimrc (and other dotfiles) open to the public. That’s a great place to draw inspiration from. For example here’s Tim Pope’s, Shougo’s and noopkat. Just go into github and search for dotfiles, then find the
.vimrc
orinit.vim
for neoVim. - Vim-bootstrap.com can generate a Vim configuration based on the type of development that you use. This can be helpful for finding useful plugins or mappings.
- vimawesome.com is a huge repository of Vim plugins. Just search by a keyword of interest and you’ll be able to find loads of plugins that can solve that problem you’re interested in.
- My Vim Plugins notes where I collect, curate and write notes about useful Vim plugins.
Tabs and Spaces
"" Global tabs/spaces
set smarttab " use spaces instead of tabs
set tabstop=2 " global tab width
set shiftwidth=2
set expandtab " use spaces instead of tabs
set laststatus=2 " Always show a status line
To convert all current existing tabs to spaces use the :retab
command. Use :h :retab
for more inof.
Configure Invisible Characters
Vim lets you configure how certain characters are displayed in your buffer window. This is specially useful for whitespace that is often not visible. To see whether you are mixing tabs and spaces or trailing whitespace you can use listcharts
:
" shows invisible characters
set list
" Configures how to visualize invisible characters
set listchars=tab:>-,trail:-,nbsp:+
Having a more comfortable leader key
The <Leader>
key in Vim allows for additional custom mappings in a convenient way by providing another modifier key (like CTRL
, SHIFT
, etc) that you can use in combination with other keys.
By default the <Leader>
is assigned to \\
which can be slightly inconvenient since it is quite far for your right pinkie finger. If that is the case, consider remapping it to another key. By far the most common custom mapping for the <Leader>
key is ,
but I find more <space>
to be more convenient (it’s always under my right thumb) and less intrussive (as it doesn’t shadow any common Vim binding that I know of). To remap <Leader>
to <space>
add this to your .vimrc
:
let mapleader="\<Space>"
Now whenever you define new bindings like this one:
nnoremap <leader><space> :noh<cr>
You can use <space>
as your leader. In this case typing <space>
twice will clear all highlighted text which you’ll typically want to do after a search.
Custom Navigation
You can add these mappings to be able to move faster than with the normal jk
commands:
nmap J 5j
nmap K 5k
This lets you move up and down in a fine grained fashion with kj
and also move faster by using KJ
just by keeping SHIFT
pressed.
There’s a caveat which is that this removes the default :join
mapping to join lines which is pretty handy (particularly when writing markdown). You can remap this using your <Leader>
key which will make joining lines more convenient:
nnoremap <Leader>j J
By default j
and k
will move up a line. However, if there is text that it is wrapped (that is, when the text is too long for the width of the window), then j
and k
will bring you up and down the complete line without taking into account wrapped lines. This is very unintuitive behavior and veeeery irritating. By default, Vim offers additional mappings gj
and gk
to go down and up a “visual line”, that is, taking into account wrapped lines. You can add these mappings to your Vim configuration to remap j
to gj
, etc and have a more intuitive default behavior:
nnoremap j gj
nnoremap k gk
nnoremap 0 g0
nnoremap ^ g^
nnoremap $ g$
Moving between windows (or buffers):
nmap gh <C-w>h
nmap gj <C-w>j
nmap gk <C-w>k
nmap gl <C-w>l
Moving between tabs:
nmap <C-l> gt
nmap <C-h> gT
Mappings To Experiment With
" using ; as : from http://stevelosh.com/blog/2010/09/coming-home-to-Vim/
" that way you avoid the need to type two letters everytime you want to
" access command mode.
" It's slightly irritating that you'll lose forward searches though
nnoremap ; :
" You can escape with <ESC> C-C or C-[ but the one below is much quicker
" Quicker escaping from http://stevelosh.com/blog/2010/09/coming-home-to-Vim/
inoremap jj <ESC>
" This doesn't work in visual mode. But in that case C-C is pretty ok
Creating custom commands
You can create your own commands in Vim by using the :command
command. For example:
" This creates a new command that can be used from
" Command-line mode by using :DeleteFirst to delete
" the first line in a buffer
:command DeleteFirst 1delete
If you want to pass arguments to your custom commands you need to use -nargs=N
to describe how many arguments your command supports:
-nargs=0
No arguments-nargs=1
One argument-nargs=*
Any number of arguments-nargs=?
Zero or one argument-nargs=+
One or more arguments
You can access those arguments from your command definition using the <args>
keyword:
:command -nargs=+ Say :echo "<args>"
<args>
comes with two siblings that can be useful in some special situations:
<q-args>
escapes all special characters in the arguments so they are represented as an string<f-args>
spreads the arguments used when calling the command so they can be used to call a function.myFunction(<f-args>)
would be equivalent tomyFunction(arg0, arg1, arg2, etc)
.
If you need to feed the result of a function into your command then you need to use execute
. execute
(See :h :execute
) allows you to compose an ex-command from evaluating an expression (in this case evaluating a function). For example:
command! -nargs=* BlogNewNotes execute "!mkdir src/pages/notes/".ReplaceSpacesWithDashes(<q-args>) | execute "e src/pages/notes/".ReplaceSpacesWithDashes(<q-args>)."/index.md"
// Function that given some text transforms it to lower case and replaces
// spaces with dashes:
// input: "Botany the study of plants"
// output: "botany-the-study-of-plants"
function ReplaceSpacesWithDashes(text)
return tolower(substitute(a:text, ' ', '-', 'g'))
endfunction
You can also take advantage of |
to execute multiple ex-commands when calling your custom command:
command! -nargs=* BlogNewNotes execute "!mkdir src/pages/notes/".ReplaceSpacesWithDashes(<q-args>) | execute "e src/pages/notes/".ReplaceSpacesWithDashes(<q-args>)."/index.md"
To list all user defined commands use the :command
command without any arguments. For more information about :command
take a look at the help :h :command
and the user manual :h 40.2
.
Language Support
Enable filetype support if you haven’t done it already:
filetype on " enable file type detection
filetype plugin on " enable loading plugins for ft
filetype indent on " enable indent per ft
Markdown
- Install the vim-markdown plugin.
- Setup vim-markdown following your needs. It comes with sensible defaults but you need to enable stuff like front-matter yaml (f.i.
let g:vim_markdown_frontmatter = 1
) - If you don’t see syntax highlighting inside fenced code blocks you may need to install a specific plugin that provides syntax highlighting for that specific language. For instance, elm-vim
Miscellaneous tips
Run Vim With Factory Settings
To run with with factory settings use the -u
option to point Vim to the following configuration file (vim -u factory.vimrc
):
# factory.vimrc
set notcompatible
filetype plugin on
or alternatively run Vim -u NONE -N
(the -N
sets notcompatible
) and then run :filetype plugin on
manually once Vim is opened.
Count words
- To find the number of words in the whole document type
g
and thenC-g
- It also works with a selection (if you select some text first)
- You can use externals programs as well
:w !wc
- For more info
:h word-count
Spellchecking
- Select language
:set spelllang=en
- Enable current session
:set spell
- Enable current buffer
:setlocal spell
]s
to move to the next misspelled word[s
to move backwardszg
to add word under cursor as a good wordzb
to add word under cursor as a bad wordz=
to get suggestions for bad words (awesome!!)- You can use counts to
2zg
set two words as good words, or1z=
select the first suggestion for a bad word - You can run autocorrection within insert mode by running
C-x
and thens
(alsoC-xC-s
). The cool thing about this one is that you don’t need to have the cursor on top of the word for it to work. You can run it at the end of a line while you’re typing and suddenly realize you made a mistake - You can set multiple spellfiles to save your own custom words based on the context or on the project you’re working on
:set spellfile+={path}/{filename}.{encoding}.add
Recovering Fleeting Error Messages When Starting Vim
If you ever run into fleeting error messages on startup try any of these:
- Using the
:messages
command which shows all warnings, errors, and informational messages that have ever appeared in the Vim statusline. (:h messages
) - The
:echo errmsg
command prints the most recent error message. - Use
g<
to see the last page of previous command output. Find out more here:h g<
.
Changing the current working directory
:pwd
shows current printing directory (it literally means print working directory):cd %:p:h
to change the current directory to the one of the opened file (%
expands to the current file,%:p
is its full path and%:p:h
refers to its directory):lcd %:p:h
does the same as above but only to the current window- More info in Vimtips
Running Multiple Commands at once
- You can run multiple Ex commands at once by separating them with the
|
operator - You can follow the same approach inside your vimrc, but you need to use the
<bar>
code to refer to|
instead of|
itself. - More Info.
Showing messages in Vim
- You can use the
:echo
command to show messages in the status bar - Alternatively, you can use
:echom
which shows a message just like:echo
and it also saves it in the history so that it can be later accessed via:messages
.
Changing Multiple Files At Once with Args List
You can change multiple files at once taking advanced of the argument list or :args
. This works great in combination with macros:
- Record a macro as usual (let’s say we’ve saved it in register
q
) - Add files you want to change to the argument list using the
:args
command. It accepts blobs. For instance:args ./**/*.markdown
adds all themarkdown
files to the argument list. - Run macro on all these files with
:argdo
like so::argdo normal @q
which means: Grab all the files in the argument list and run the:normal @q
command which in essence consists in running@q
in normal mode.
You can also edit files in the argument list one by one like so:
- Add files you want to change to the argument list using
:args
. For instance,:args ./**/*.markdown
. - The first file that matches the blob is opened automatically when running the command above.
- Make necessary changes and type
:wn
(write next) (:h :wn
) to save and jump to the next file in the argument list.
Some helpful argument list commands for reference:
:args
- check what’s in the argument list:args {file}
- adds file to argument list:args {blob}
- adds files matching blob to argument list:sall
- open files in argument list in horizontal splits:all
- open files in argument list in vertical splits
For more info check out :h :args
.
Searchng for Patterns using Vimgrep
Vim comes with grep-like functionality in the form of the :Vimgrep
command. You can use it like so:
:Vimgrep /{pattern}/ files
Where {pattern}
is a regular expression and files
is a glob of files. For instance:
:Vimgrep /draft: false/ ./**/*.markdown
Searches all mardown files for the string draft: false
.
Vimgrep populates the quickfix list with all matches (run :copen
to see all matches within a window) and sends you to the first match if at least one is found.
For more info about Vimgrep check the help :h :Vimgrep
and :h quickfix
.
Inserting Unicode Characters in Vim
You can insert unicode characters in Vim using the unicode character code by typijng: <C-V>u{code}
. This is super helpful when you want to insert unicode code characters for icon fonts to make your Vim experience be nicer.
Interesting Tips from Vim’s Help
Jump to a subject: Position the cursor on a tag (e.g. |bars|) and hit CTRL-]
. Use CTRL-T
or CTRL-O
to come back to the original position
Getting Specific Help With Context
It is possible to go directly to whatever you want help on, by giving an argument to the |:help| command. It is possible to further specify the context:
WHAT PREPEND EXAMPLE ~
Normal mode command (nothing) :help x
Visual mode command v_ :help v_u
Insert mode command i_ :help i_<Esc>
Command-line command : :help :quit
Command-line editing c_ :help c_<Del>
Vim command argument - :help -r
Option ' :help 'textwidth'
Syntax Highlighting
Syntax highlighting in Vim works in the following manner:
- You create syntax groups with
:syntax
to match the syntax of a given language (most of the times you can ust reuse syntax groups that come with Vim or provided by a plugin) - You create highlighting groups with
:highlight
to connect syntax to highlighting styles.
For more info, check the user manual at :h usr_44
.
Showing Invisible Characters
- To show invisible characters use
:set list
- To hide them use
:set nolist
- You can find more information in
:help :list
and:help 'list'
Resources
- Vim Help (in Vim
:help
) - Vimtutor (in a shell type
Vimtutor
, within neoVim type:Tutor
) - Vim Tips wiki
- (Book)Practical Vim. See updates in second edition
- Modern Vim: Craft Your Development Environment with Vim 8 and NeoVim
- Other interesting articles:
- Other interesting resources
- Vim cheatsheet
Interesting Talks on Vim
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.