---
visibility: public
---

# Vim

**repo:** [mhinz/vim-galore](https://github.com/mhinz/vim-galore)  
**category:** [[editors|Editors]]
**related:** [[neovim|Neovim]] · [[emacs|Emacs]] · [[sublime-text|Sublime Text]]

---

### [Intro](#intro-1)

- [What is Vim?](#what-is-vim)
- [The Vim Philosophy](#the-vim-philosophy)
- [First steps](#first-steps)
- [Minimal vimrc](#minimal-vimrc)
- [What kind of Vim am I running?](#what-kind-of-vim-am-i-running)
- [Cheatsheets](#cheatsheets)

### [Basics](#basics-1)

- [Buffers, [windows](/@harrisonqian/awesome/wiki/platforms/windows), tabs](#buffers-windows-tabs)
- [Active, loaded, listed, named buffers](#active-loaded-listed-named-buffers)
- [Argument list](#argument-list)
- [Mappings](#mappings)
- [Mapleader](#mapleader)
- [Registers](#registers)
- [Ranges](#ranges)
- [Marks](#marks)
- [Completion](#completion)
- [Motions, operators, text objects](#motions-operators-text-objects)
- [Autocmds](#autocmds)
- [Changelist, jumplist](#changelist-jumplist)
- [Undo tree](#undo-tree)
- [Quickfix and location lists](#quickfix-and-location-lists)
- [Macros](#macros)
- [Colorschemes](#colorschemes)
- [Folding](#folding)
- [Sessions](#sessions)
- [Locality](#locality)

### [Usage](#usage-1)

- [Getting help offline](#getting-help-offline)
- [Getting help offline (alternative)](#getting-help-offline-alternative)
- [Getting help online](#getting-help-online)
- [Autocmds in practice](#autocmds-in-practice)
  - [User events](#user-events)
  - [Nested autocmds](#nested-autocmds)
- [Clipboard](#clipboard)
  - [Clipboard usage (Windows, macOS)](#clipboard-usage-[windows](/@harrisonqian/awesome/wiki/platforms/windows)-macos)
  - [Clipboard usage (Linux, BSD, ...)](#clipboard-usage-[linux](/@harrisonqian/awesome/wiki/platforms/linux)-bsd-)
- [Restore cursor position when opening file](#restore-cursor-position-when-opening-file)
- [Temporary files](#temporary-files)
  - [Backup files](#backup-files)
  - [Swap files](#swap-files)
  - [Undo files](#undo-files)
  - [Viminfo files](#viminfo-files)
  - [Example configuration for temporary files](#example-configuration-for-temporary-files)
- [Editing remote files](#editing-remote-files)
- [Managing plugins](#managing-plugins)
- [Block insert](#block-insert)
- [Running external programs and using filters](#running-external-programs-and-using-filters)
- [Cscope](#cscope)
- [MatchIt](#matchit)
- [True colors](#true-colors)

### [Tips](#tips-1)

- [Go to other end of selected text](#go-to-other-end-of-selected-text)
- [Saner behavior of n and N](#saner-behavior-of-n-and-n)
- [Saner command-line history](#saner-command-line-history)
- [Saner CTRL-L](#saner-ctrl-l)
- [Disable audible and visual bells](#disable-audible-and-visual-bells)
- [Quickly [move](/@harrisonqian/awesome/wiki/programming-languages/move) current line](#quickly-move-current-line)
- [Quickly add empty lines](#quickly-add-empty-lines)
- [Quickly edit your macros](#quickly-edit-your-macros)
- [Quickly jump to header or source file](#quickly-jump-to-header-or-source-file)
- [Quickly change font size in GUI](#quickly-change-font-size-in-gui)
- [Change cursor style dependent on mode](#change-cursor-style-dependent-on-mode)
- [Don't lose selection when shifting sidewards](#dont-lose-selection-when-shifting-sidewards)
- [Reload a file on saving](#reload-a-file-on-saving)
- [Smarter cursorline](#smarter-cursorline)
- [Faster keyword completion](#faster-keyword-completion)
- [Cosmetic changes to colorschemes](#cosmetic-changes-to-colorschemes)

### [Commands](#commands-1)

- [:global and :vglobal](#global-and-vglobal) - Execute a command on all matching lines.
- [:normal and :execute](#normal-and-execute) - The scripting dream team.
- [:redir and execute()](#redir-and-execute) - Capture command output.

### [Debugging](#debugging-1)

- [General tips](#general-tips)
- [Verbosity](#verbosity)
- [Profiling startup time](#profiling-startup-time)
- [Profiling at runtime](#profiling-at-runtime)
- [Debugging Vim scripts](#debugging-vim-scripts)
- [Debugging syntax files](#debugging-syntax-files)

### [Miscellaneous](#miscellaneous-1)

- [Additional resources](#additional-resources)
- [Vim distributions](#vim-distributions)
- [Standard plugins](#standard-plugins)
- [Map CapsLock to Control](#map-capslock-to-control)
- [Generating HTML from buffer](#generating-html-from-buffer)
- [Easter eggs](#easter-eggs)
- [Why hjkl for navigation?](#why-hjkl-for-navigation)

### [Common problems](#common-problems-1)

- [Editing small files is slow](#editing-small-files-is-slow)
- [Editing huge files is slow](#editing-huge-files-is-slow)
- [Bracketed paste (or why do I have to set 'paste' all the time?)](#bracketed-paste-or-why-do-i-have-to-set-paste-all-the-time)
- [Delays when using escape key in terminal](#delays-when-using-escape-key-in-terminal)
- [Function search undo](#function-search-undo)

### [Technical quirks](#technical-quirks-1)

- [Newline used for NUL](#newline-used-for-nul)

### [Terminology](#terminology-1)

- [Vim script? Vimscript? VimL?](#vim-script-vimscript-viml)

### [List of colorschemes](PLUGINS.md#colorschemes-1)

### [List of plugins](PLUGINS.md)

<br>

# Intro

## What is Vim?

[Vim](http://www.vim.org) is a text editor with a long line of ancestors that
goes back to [qed](https://en.wikipedia.org/wiki/QED_(text_editor)). [Bram
Moolenaar](https://en.wikipedia.org/wiki/Bram_Moolenaar) released it in 1991.

The project is hosted online at [vim.org](http://www.vim.org/index.php).

Getting Vim: Use your favourite package manager or visit the [download
page](http://www.vim.org/download.php) from vim.org.

Discussions and user questions are best done on the
[vim_use](https://groups.google.com/forum/#!forum/vim_use) mailing list or using
IRC ([Freenode](https://freenode.net)) in the `#vim` channel.

Development happens on [GitHub](https://github.com/vim/vim), discussions on the
[vim_dev](https://groups.google.com/forum/#!forum/vim_dev) mailing list.

Read [Why, oh WHY, do those #?@! nutheads use
vi?](http://www.viemu.com/a-why-vi-vim.html) to see common misconceptions about
Vim explained.

## The Vim Philosophy

Vim adheres to the modal editing philosophy. This means that it provides
multiple modes and the meaning of keys changes according to the mode. You
navigate files in _normal mode_, you insert text in _insert mode_, you select
lines in _visual mode_, you access commands in _command-line mode_ and so on.
This might sound complicated at first, but has a huge advantage: you don't have
to break your fingers by holding several keys at once, most of the time you
simply press them one after the other. The more common the task, the fewer keys
are needed.

A related concept that works well with modal editing are operators and motions.
_Operators_ start a certain action, e.g. changing, removing, or selecting text.
Afterwards you specify the region of text you want to act on using a _motion_.
To change everything between parentheses, use `ci(` (read _change inner
parentheses_). To remove an entire paragraph of text, use `dap` (read _delete
around paragraph_).

If you see advanced Vim users working, you'll notice that they speak the
_language of Vim_ as well as pianists handle their instruments. Complex
operations are done using only a few key presses. They don't even think about it
anymore as [muscle memory](https://en.wikipedia.org/wiki/Muscle_memory) took
over already. This reduces [cognitive
load](https://en.wikipedia.org/wiki/Cognitive_load) and helps to focus on the
actual task.

## First steps

Vim comes bundled with an interactive tutorial that teaches the most basic
things you need to know about. You can start it from the shell:

```
$ vimtutor
```

Don't be put off by how boring it looks like and work through the exercises. The
editors or IDEs you used before were most probably all non-modal, so working by
switching modes will seem awkward at first, but the more you use Vim, the more
it becomes [muscle memory](https://en.wikipedia.org/wiki/Muscle_memory).

Vim was bolted on [Stevie](https://en.wikipedia.org/wiki/Stevie_(text_editor)), a
[vi](https://en.wikipedia.org/wiki/Vi) clone, and supports two operating modes:
"compatible" and "nocompatible". Using Vim in compatible mode means using vi
defaults for all options, opposed to Vim defaults. As long as you didn't create
a user vimrc yet or started Vim with `vim -N`, compatible mode is assumed! Don't
use Vim in compatible mode. Just don't.

Next steps:

1. Create your own [vimrc](#minimal-vimrc).
2. Have some [cheatsheets](#cheatsheets) ready for the first weeks.
3. Read through the [basics](#basics-1) section to learn what is even possible.
4. Learn on demand! You never finish learning Vim. If you encounter any
   problems, just look for it on the internet. Your problem was solved already.
   Vim comes with great documentation and knowing how to navigate it is a must:
   [Getting help offline](#getting-help-offline).
5. Have a look at the [additional resources](#additional-resources).

One last advice: Please learn how to use Vim properly before starting to add all
kinds of hyped [plugins](#managing-plugins) that only implement features that
Vim already supports natively.

## Minimal vimrc

The user vimrc can be put into `~/.vimrc` or for the sake of better separation
into `~/.vim/vimrc`. The latter makes it easy to put the entire configuration
under version control and upload it to, let's say GitHub.

You find many "minimal vimrcs" all over the net, and maybe my version isn't as
minimal as it should be, but it provides a good set of sane settings that I deem
to be useful for starting out.

Eventually you have to read up on all the mentioned settings anyway and decide
for yourself. :-)

So here it is: [minimal-vimrc](static/minimal-vimrc.vim)

In case you're interested, here's
[my vimrc](https://github.com/mhinz/dotfiles/blob/master/.vim/vimrc).

**TIP**: Most plugin authors maintain several plugins and also publish their
vimrc on GitHub (often in a repository called "vim-config" or "dotfiles"), so
whenever you find a plugin you like, look up its maintainer's GitHub page and
look through the repositories.

## What kind of Vim am I running?

Looking at `:version` will give you all the information you need to know about
how the currently running Vim binary was compiled.

The first line tells you when the binary was compiled and the version, e.g. 7.4.
One of the next lines states `Included patches: 1-1051`, which is the patch
level. Thus, your exact Vim version is 7.4.1051.

Another line states something like `Tiny version without GUI` or `Huge version
with GUI`. The obvious information from that is whether your Vim includes GUI
support, e.g. for starting `gvim` from the shell or running `:gui` from Vim
within a terminal emulator. The other important information is the `Tiny` and
`Huge`. Vim distinguishes between feature sets called `tiny`, `small`, `normal`,
`big`, and `huge`, all enabling different subsets of features.

The majority of `:version` output is consumed by the feature list itself.
`+clipboard` means the clipboard feature was compiled in, `-clipboard` means it
wasn't compiled in.

A few Vim features need to be compiled in for them to work. E.g. for `:prof` to
work, you need a Vim with a huge feature set, because that set enables the
`+profile` feature.

If that's not the case and you installed Vim from a package manager, make sure
to install a package called `vim-x`, `vim-x11`, `vim-gtk`, `vim-gnome` or
similar, since these packages usually come with the huge feature set.

You can also test for the version or features programmatically:

```vim
" Do something if running at least Vim 7.4.42 with +profile enabled.
if (v:version > 704 || v:version == 704 && has('patch42')) && has('profile')
  " do stuff
endif
```

Help:

```
:h :version
:h feature-list
:h +feature-list
:h has-patch
```

## Cheatsheets

- http://people.csail.mit.edu/vgod/vim/vim-cheat-sheet-en.png
- https://cdn.shopify.com/s/files/1/0165/4168/files/preview.png
- http://michael.peopleofhonoronly.com/vim/vim_cheat_sheet_for_programmers_screen.png
- http://www.rosipov.com/images/posts/vim-movement-commands-cheatsheet.png

Or quickly open a cheatsheet from within Vim: [vim-cheat40](https://github.com/lifepillar/vim-cheat40).

# Basics

## Buffers, windows, tabs

Vim is a text editor. Every time text is shown, the text is part of a
**buffer**. Each file will be opened in its own buffer. Plugins show stuff in
their own buffers etc.

Buffers have many attributes, e.g. whether the text it contains is modifiable,
or whether it is associated with a file and thus needs to be synchronized to
disk on saving.

**Windows** are viewports _onto_ buffers. If you want to view several files at
the same time or even different locations of the same file, you use windows.

And please, please don't call them _splits_. You can split a window in two, but
that doesn't make them _splits_.

Windows can be split vertically or horizontally and the heights and widths of
existing windows can be altered, too. Therefore, you can use whatever window
layout you prefer.

A **tab page** (or just tab) is a collection of windows. Thus, if you want to
use multiple window layouts, use tabs.

Putting it in a nutshell, if you start Vim without arguments, you'll have one
tab page that holds one window that shows one buffer.

By the way, the buffer list is global and you can access any buffer from any
tab.

## Active, loaded, listed, named buffers

Run Vim like this `vim file1`. The file's content will be loaded into a buffer.
You have a **loaded buffer** now. The content of the buffer is only synchronized
to disk (written back to the file) if you save it within Vim.

Since the buffer is also shown in a window, it's also an **active buffer**. Now
if you load another file via `:e file2`, `file1` will become a **hidden buffer**
and `file2` the active one.

Both buffers are also **listed**, thus they will get listed in the output of
`:ls`. Plugin buffers or help buffers are often marked as unlisted, since
they're not regular files you usually edit with a text editor. Listed and
unlisted buffers can be shown via `:ls!`.

**Unnamed buffers**, also often used by plugins, are buffers that don't have an
associated filename. E.g. `:enew` will create an unnamed scratch buffer. Add
some text and write it to disk via `:w /tmp/foo`, and it will become a named
buffer.

## Argument list

The [global buffer list](#buffers-windows-tabs) is a Vim thing. Before that, in
vi, there only used to be the argument list, which is also available in Vim.

Every filename given to Vim on the shell command-line, is remembered in the
argument list. There can be multiple argument lists: by default all arguments
are put into the global argument list, but you can use `:arglocal` to create a
new argument list that is local to the window.

List the current arguments with `:args`. Switch between files from the argument
list with `:next`, `:previous`, `:first`, `:last` and friends. Alter it with
`:argadd`, `:argdelete` or `:args` with a list of files.

If you should prefer using the buffer or argument list for working with files is
a matter of taste. My impression is that most people use the buffer list
exclusively.

Nevertheless, there is one huge use case for the argument list: batch processing
via `:argdo`! A simple refactoring example:

```vim
:args **/*.[ch]
:argdo %s/foo/bar/ge | update
```

This replaces all occurrences of "foo" by "bar" in all C source and header files
from the current directory and below.

Help: `:h argument-list`

## Mappings

You can define your own mappings with the `:map` family of commands. Each
command of that family defines a mapping for a certain set of modes. Technically
Vim comes with a whopping 12 modes, 6 of them can be mapped. Additionally, some
commands act on multiple modes at once.

| Recursive | Non-recursive | Unmap     | Modes                            |
|-----------|---------------|-----------|----------------------------------|
| `:map`    | `:noremap`    | `:unmap`  | normal, visual, operator-pending |
| `:nmap`   | `:nnoremap`   | `:nunmap` | normal                           |
| `:xmap`   | `:xnoremap`   | `:xunmap` | visual                           |
| `:cmap`   | `:cnoremap`   | `:cunmap` | command-line                     |
| `:omap`   | `:onoremap`   | `:ounmap` | operator-pending                 |
| `:imap`   | `:inoremap`   | `:iunmap` | insert                           |

E.g. this defines the mapping for normal mode only:

```vim
:nmap <space> :echo "foo"<cr>
```

Unmap it again by using `:nunmap <space>`.

For a few more but rather uncommon modes (or combinations of them), see `:h
map-modes`.

So far, so good. There's only one problem that can be pretty confusing to
beginners: `:nmap` is _recursive_! That is, the right-hand side takes other
mappings into account.

So you defined a mapping that simply echoes "Foo":

```vim
:nmap b :echo "Foo"<cr>
```

But what if you want to map the default behavior of `b` (going one word back) to
another key?

```vim
:nmap a b
```

If you hit <kbd>a</kbd>, we expect the cursor to go back a word, but instead
"Foo" is printed in the command-line! Because the right-hand side, `b`, was
mapped to another action already, namely `:echo "Foo"<cr>`.

The proper way to resolve this problem is to use a _non-recursive_ mapping
instead:

```vim
:nnoremap a b
```

Rule of thumb: Always use non-recursive mappings unless recursing is actually
desired.

Look up your mappings by not giving a right-hand side. E.g. `:nmap` shows all
normal mappings and `:nmap <leader>` shows all normal mappings that start with
the mapleader.

If you want to disable a standard mapping, map them to the special `<nop>`
character, e.g. `:noremap <left> <nop>`.

Help:

    :h key-notation
    :h mapping
    :h 05.3

## Mapleader

The mapleader is simply a placeholder than can be used with custom mappings and
is set to `\` by default.

```vim
nnoremap <leader>h :helpgrep<space>
```

This mapping is triggered by `\h`. If you want to use `<space>h` instead:

```vim
let mapleader = ' '
nnoremap <leader>h :helpgrep<space>
```

Moreover, there is `<localleader>` that is the local counterpart to `<leader>`
and is supposed to be used for mappings that are local to the buffer, eg.
filetype-specific plugins. It also defaults to `\`.

**Note**: Set the mapleaders before mappings! All leader mappings that are in
effect already, won't change just because the mapleader was changed. `:nmap
<leader>` will show all normal mode leader mappings with the mapleader resolved
already, so use it to double-check your mappings.

See `:h mapleader` and `:h maplocalleader` for more.

## Registers

Registers are slots that save text. Copying text into a register is called
**yanking** and extracting text from a register is called **pasting**.

Vim provides the following registers:

| Type                | Character              | Filled by? | Readonly? | Contains text from? |
|---------------------|------------------------|------------|-----------|---------------------|
| Unnamed             | `"`                    | vim        | [ ]       | Last yank or deletion. (`d`, `c`, `s`, `x`, `y`) |
| Numbered            | `0` to `9`             | vim        | [ ]       | Register `0`: Last yank. Register `1`: Last deletion. Register `2`: Second last deletion. And so on. Think of registers `1`-`9` as a read-only [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) with 9 elements. |
| Small delete        | `-`                    | vim        | [ ]       | Last deletion that was less than one line. |
| Named               | `a` to `z`, `A` to `Z` | user       | [ ]       | If you yank to register `a`, you replace its text. If you yank to register `A`, you append to the text in register `a`. |
| Read-only           | `:`, `.`, `%`          | vim        | [x]       | `:`: Last command, `.`: Last inserted text, `%`: Current filename. |
| Alternate buffer    | `#`                    | vim        | [ ]       | Most of the time the previously visited buffer of the current window. See `:h alternate-file` |
| Expression          | `=`                    | user       | [ ]       | Evaluation of the VimL expression that was yanked. E.g. do this in insert mode: `<c-r>=5+5<cr>` and "10" will be inserted in the buffer. |
| Selection           | `+`, `*`               | vim        | [ ]       | `*` and `+` are the [clipboard](#clipboard) registers. |
| Drop                | `~`                    | vim        | [x]       | From last drag'n'drop. |
| Black hole          | `_`                    | vim        | [ ]       | If you don't want any other registers implicitly affected. E.g. `"_dd` deletes the current line without affecting registers `"`, `1`, `+`, `*`. |
| Last search pattern | `/`                    | vim        | [ ]       | Last pattern used with `/`, `?`, `:global`, etc. |

Each register that is not readonly can be set by the user:

```vim
:let @/ = 'register'
```

Afterwards <kbd>n</kbd> would jump to the next occurrence of "register".

There are numerous exceptions when registers get implicitly filled, so be sure
to read `:h registers`.

Yank with `y` and paste with `p`/`P`, but mind that Vim distinguishes between

---
*truncated — [full list on GitHub](https://github.com/mhinz/vim-galore)*
