Vim
repo: mhinz/vim-galore
category: Editors
related: Neovim · Emacs · Sublime Text
Intro
- What is Vim?
- The Vim Philosophy
- First steps
- Minimal vimrc
- What kind of Vim am I running?
- Cheatsheets
Basics
- [Buffers, windows, tabs](#buffers-windows-tabs)
- Active, loaded, listed, named buffers
- Argument list
- Mappings
- Mapleader
- Registers
- Ranges
- Marks
- Completion
- Motions, operators, text objects
- Autocmds
- Changelist, jumplist
- Undo tree
- Quickfix and location lists
- Macros
- Colorschemes
- Folding
- Sessions
- Locality
Usage
- Getting help offline
- Getting help offline (alternative)
- Getting help online
- Autocmds in practice
- Clipboard
- Restore cursor position when opening file
- Temporary files
- Editing remote files
- Managing plugins
- Block insert
- Running external programs and using filters
- Cscope
- MatchIt
- True colors
Tips
- Go to other end of selected text
- Saner behavior of n and N
- Saner command-line history
- Saner CTRL-L
- Disable audible and visual bells
- [Quickly move current line](#quickly-move-current-line)
- Quickly add empty lines
- Quickly edit your macros
- Quickly jump to header or source file
- Quickly change font size in GUI
- Change cursor style dependent on mode
- Don't lose selection when shifting sidewards
- Reload a file on saving
- Smarter cursorline
- Faster keyword completion
- Cosmetic changes to colorschemes
Commands
- :global and :vglobal - Execute a command on all matching lines.
- :normal and :execute - The scripting dream team.
- :redir and execute() - Capture command output.
Debugging
- General tips
- Verbosity
- Profiling startup time
- Profiling at runtime
- Debugging Vim scripts
- Debugging syntax files
Miscellaneous
- Additional resources
- Vim distributions
- Standard plugins
- Map CapsLock to Control
- Generating HTML from buffer
- Easter eggs
- Why hjkl for navigation?
Common problems
- Editing small files is slow
- Editing huge files is slow
- Bracketed paste (or why do I have to set 'paste' all the time?)
- Delays when using escape key in terminal
- Function search undo
Technical quirks
Terminology
List of colorschemes
List of plugins
<br>
Intro
What is Vim?
Vim is a text editor with a long line of ancestors that goes back to qed. Bram Moolenaar released it in 1991.
The project is hosted online at vim.org.
Getting Vim: Use your favourite package manager or visit the download page from vim.org.
Discussions and user questions are best done on the
vim_use mailing list or using
IRC (Freenode) in the #vim channel.
Development happens on GitHub, discussions on the vim_dev mailing list.
Read Why, oh WHY, do those #?@! nutheads use vi? 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 took over already. This reduces 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.
Vim was bolted on Stevie, a
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:
- Create your own vimrc.
- Have some cheatsheets ready for the first weeks.
- Read through the basics section to learn what is even possible.
- 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.
- Have a look at the additional resources.
One last advice: Please learn how to use Vim properly before starting to add all kinds of hyped 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
In case you're interested, here's my 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:
" 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.
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 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:
: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:
: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":
:nmap b :echo "Foo"<cr>
But what if you want to map the default behavior of b (going one word back) to
another key?
: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:
: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.
nnoremap <leader>h :helpgrep<space>
This mapping is triggered by \h. If you want to use <space>h instead:
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 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 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:
: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