VIM in my muscle memory
I have been an ardent VIM user for almost 4 years now, and it’s been a while since I have been wanting to write this Blog. My motivation is not to showoff or to start any flame war against any other popular text editors that may or may not be better ;), but to simply showcase the things I like and have come to appreciate in VIM, and show why you should seriously consider it when deciding which programming editor you should use. Hopefully I will be able to do justice to VIM - the Ultimate Programmer’s Editor.
The beauty about using VIM is that it converts the task of text editing / manipulation into a programmable activity. It provides you with a framework to work with your text in a way which allows you to think of it in terms of simple patterns, patterns which you can repeat, store (macros), copy & combine together. This also makes the process of learning VIM interesting & fun! Add to that the fact that you can easily extend your VIM with a wide variety of plugins & themes contributed and shared openly by a vibrant community is just icing on the cake!
Initially when you start out with VIM it feels quite alien and ancient to say the least, also because the default configurations in VIM aren’t that optimal, so it might take a few days to get a hang of things, but once you do, it will motivate you to do things faster. The more you do, the more you obsess on doing things faster and with fewer and fewer keystrokes as possible (1)You might want to have a look at VIM Golf for a bit of fun in that respect :)) the more you discover what VIM has to offer
Over a prolonged period of usage, slowly and steadily VIM commands creep into your muscle memory and the vastness of the abilities and features of VIM which overwhelm you in the beginning, come to you as second nature. This is my attempt to describe various elements of VIM that are now in my muscle memory and use them on a daily basis.
VIM is capable of so much that summing it all up in a few blog posts is just impossible, it can’t do justice to it’s capabilities, it is no wonder that people have written entire books on how to use VIM. In my post I will just be covering a few of the basics of VIM that I have come to appreciate and use. Before I go ahead with that, here is a list of a few resources that have been helpful :
- Seven habits of effective text editing by VIM author Bram Moolenaar
- vimtutor
- VIM Wiki
- VIM Trail Map by ThoughtBot
- UseVim
- Vim Coderwall
vimtutor, I would encourage everyone to go through it at least once. I often go and refer to the help from time to time while (re)discovering things. Another point to note is that VIM’s help is one of the most impressive help system I have EVER come across. I doubt if any help system for any software can ever be any better :). Now i’ll just iterate a few basic usage patterns and concepts that I use on a daily basis.
- Search: This is one of the most powerful features of VIM, searching
a document for a text is usually one of the most basic & frequent tasks one
does and VIM makes it incredibly fast & simple. The best part is that it
accepts regular expressions, so can come in rather handy at times.
- /{pattern}: Does a forward search from the cursor for
{pattern}
in the current buffer. You can then jump between the various occurrences of your search pattern using n (forward) or N (backward). If you have enabled theincsearch
option, VIM will show the first match of your pattern as you type. If you set theignorecase
option, VIM will disregard the case of your search pattern, but an even neater option issmartcase
, setting which VIM will do a case sensitive search when the pattern has both upper and lower case characters and ignore case if it is all in lower or upper case. If you set thehlsearch
option, VIM will highlight all your search matches. VIM also allows for various special characters preceeded with a backslash within the search pattern that can help you create really incredibly accurate searches. Although there is a huge list of such patterns, a few of those that I use regularly are\zs
&\ze
, this essentially helps be define where the actual match pattern starts and ends within the complete{pattern}
, eg.)/def\zsawesome_method\ze
, here as you can see although you search for a pattern starting with def, the actual match pattern is awesome_method and VIM will match & highlight only these words, though cycle through complete matches only, i.e. beginning with def. This can come in useful when you wish to match only function definitions rather than all calls to the function. - ?{pattern}: Same as /{pattern}, but searches backwards from the cursor.
- *: For an instant forward search of the word under the cursor. This takes the cursor directly to the location of the next match.
- #: Same as *, but searches backwards.
- g*: This is similar to * except that it doesn’t do a complete word match, hence it would also match words with a partial match to the word under the cursor. eg.) if the word under the cursor is ‘rain’, g* will also match the word rainbow.
- g#: Similar to g*, but searches backwards.
- /{pattern}: Does a forward search from the cursor for
- Commands: In VIM you manipulate text with the help of commands in
normal mode or visual mode, you combine an operator with
a motion command along with an optional count
(2)To
indicate how many times you wish to repeat the command
to
manipulate your text. A simple example is dw
, here
d
is the operator which logically is for deletion and
w
is the motion which logically stands for word, used to
move to the next word. So dw
can be expanded in plain
english as ‘delete word’, and the command does exactly that, it deletes
a word. You can also use 2dw
to tell VIM to repeat the
command dw
twice, and you can also use the command
d2w
which can be read as ‘delete 2 words’. Although the
count can be placed both after and before the operator, the effect it
produces varies with usage. You can also say 3d2w
which
will then repeat the command d2w
3 times, and hence
effectively deleting 6 words (delete 2 words 3 times). A similar pattern can
be applied to all operators. For visual mode the operator will be applied
to the selected text.
- Operators: VIM offers several operators which are all mapped very
logically to the right characters and hence make the commands very easy to
remember. You use operators with motions to form a command.
- d : Delete.
- x : Delete character under cursor, alternatively you can use X to delete character before cursor (like backspace), same as doing dl / d<Right> . Since this changes text instantly you can’t apply this with motion commands, for that you use d .
- c : Change, this command when used takes you into insert mode after completion. eg.) cw will delete a word and go into insert mode for you to type.
- s : Substitute, delete a single character and go into insert mode, same as doing cl / c<Right> , only a keystroke shorter. Like x this can’t be applied with motion commands, use c for that instead.
- y : Yank (Copy).
- r{char}
: replace character under cursor with
{char}
. Same as s{char}<Esc> since it doesn’t take you into insert mode. You can use command R to go into replace mode in which everything you type will replace the existing text until you press <Esc> to come back to normal mode. - ~ : Swap case, you can also use gu to make lowercase and gU to make uppercase.
- > : Shifts line(s) right. Comes in very handy for indenting line(s).
- < : Shifts line(s) left.
- =
: This formats your code and indents it nicely,
usually it follows C-indenting by default, but it uses
equalprg
option to filter through in case it’s defined, syntax files for common languages often define this. Often when editing files written by others in misconfigured editors, I use gg=G to format the entire file. - gq : This is nifty for formatting text, I use it often to split long lines into multiple lines each containing ‘textwidth’ option number of characters per line.
- Motions: Note that searches are also considered as motions and can be applied with operators.
- Basic cursor movements:
- h : Move left by a character.
- j : Move down a line. You can use gj to move down a wrapped line on screen.
- k : Move up a line. You can use gk to move up a wrapped line on screen.
- l : Move right by a character. In VIM it is recommanded that you use these h , j , k , l keys to move around. The idea is that your hands should always remain on the keyboard, so whether you are typing any commands or motions or typing text in insert mode, your hands are always in the same position and so no time is wasted in moving your hands. You may use the arrow keys too, but it is not recommended.
- 0 : Move to the start of the line. You can use g0 to go to go to the start of a wrapped line in the screen.
- ^ / <Home> : Move to the first character in the line. You can use g^ to go to the first character of a wrapped line on the screen.
- $ / <End> : Move to the end of line. You can use g$ to go to the last character of a wrapped line on the screen.
- Text Motions: You can these to simply move around a document based on the text, you can use a countbefore them to repeat multiple times, you can also use them after typing an operator in which case it will be used to determine what text the operator would be applied to.
- w : Moves to the next word
- W : Moves to the next full word. eg.) ‘sp;ecial text’ if your cursor is on the letter ’s’, w will take you to ‘;’ character whereas pressing W will take you to the ’t’ character (first character of word text).
- e : Moves till the end of the word.
- E : Moves till the end of the full word, like W
- b : Moves back a word.
- B : Moves back a full word.
- f{char} : Moves to the next occurrence of {char}, read as find {char}.
- F{char} : Moves to the previous occurrence of {char}.
- t{char} : Same as f{char} , but moves the cursor one character left of {char}, read as till {char}.
- T{char} : Same as F{char} , but moves the cursor one character right of {char}.
- ) : Moves forwards to the next sentence. Sentences are separated by a full-stop.
- ( : Moves backwards to the previous sentence.
- } : Moves forward to the next paragraph. Paragraphs are separated by a new line.
- { : Moves back to the previous paragraph.
- % : This is really cool & useful, it moves you to the matching close / opening brackets - (,),{,},[,]. The beauty about VIM is that all of these commands can be extended to suit our needs. Basic VIM plugins like for ruby, html and other file types exist which extend the % to match a lot more than just brackets, like for instance you can match if - else - end, or you can match html tags <div> - </div>, etc, always comes in very handy.
- H : Move cursor to the top of the window.
- M : Move cursor to the middle of the window.
- L : Move cursor to the bottom of the window.
- Scrolling:
- Ctrl-E : Scroll down a line.
- Ctrl-Y : Scroll up a line.
- Ctrl-D : Scroll down by a number of lines defined by the ‘scroll’ option.
- Ctrl-U : Scroll up by a number of lines defined by the ‘scroll’ option.
- Ctrl-F : Scroll down an entire page. Same as Shift-Down* & PageDown .
- Ctrl-B : Scroll up an entire page. Same as Shift-Up & PageUp .
- zt : Scroll up such that the current line becomes the top line.
- zz : Scroll such that the current line becomes the middle line.
- zb : Scroll such that the current line becomes the bottom line.
- Text Objects: These are used for text selection and can be used in
visual mode or after an operator only. These are really useful, since they
allow you to affect text logically without being on a specific position.
These are essentially of two types, starting with i
or
a
. You can read i
as inner and
a
simply as a.
- iw
: inner word, eg).
$wo\underline{r}d$
, if your cursor is on the letter ‘r’ and you say diw , it will delete the entire word. - aw : a word, deletes surrounding space as well.
- iW : inner full word.
- aW : a full word.
- is : inner sentence.
- as : a sentence.
- ip : inner paragraph.
- ap : a paragraph.
- i[ / i] : inner [] block, would select everything within the [].
- a[ / a] : a [] block, selection includes the [].
- i{ / i} : inner {} block.
- a{ / a} : a {} block.
- i( / i) : inner () block.
- a( / a) : a () block.
- i< / i> : inner <> block.
- a< / a> : a <> block.
- it : inner html tag, very useful while editing html / xml documents.
- at : a html tag.
- i' / i" / i` : inner quote. This is very useful when editing strings. Simply say ci' to delete the text within the ’ quote and type in something new.
- a' / a" / a` : a quote.
- iw
: inner word, eg).
- Marks : This is a very useful feature in VIM.
m{a-zA-Z}
sets a mark at the current cursor position.
You can move to the mark location in two ways ‘{a-zA-Z}
to move to the line of the mark and `{a-zA-Z}
to move
to the exact cursor location of the mark. This can come in very handy if
you want to quickly move between two specific locations within the same
file. There are also a few special marks maintained internally by VIM :
- ‘< / `< : Moves to the first line / character of the last selected visual area. If you select text in visual mode and type ‘:’, you will notice that VIM automatically adds :’<,’> in your command line, what that means is that whatever Ex command you execute would then be applied to that range.
- ‘> / `> : Moves to the last line / character of the last selected visual area.
- '' / `` : This is incredibly useful, it moves you to the previous line / cursor location.
- ‘" / `" : Moves you to the line / cursor location you were in when last exiting that buffer.
- ‘. / `. : This is another very useful one, it will jump to the line / character where you made the last change.
- Jumps: VIM identifies a ‘jump’ if we use one of the following
commands: '
, `
,
G
, /
, ?
,
n
, N
, %
,
(
, )
, [[
,
]]
, {
, }
,
:
, :tag
, L
,
M
, H
. If you make the cursor jump
with one of these commands, VIM will remember them and maintain a list.
You can use the following commands to traverse through the jumps :
- Ctrl-o : Go to previous jump location.
- Ctrl-i : Go to the next jump location.
- Basic cursor movements:
- Special Commands: VIM offers various special commands that are useful
for doing simple things quickly.
- dd : delete the line under the cursor, something that I use very often.
- D : delete from the cursor location to the end of line.
- yy : yank (copy) the current line.
- cc : change the current line.
- C : change from the cursor location to the end of line.
- gg : go to the first line of the document.
- [count]G : go to the count line, without the count it will take you to the last line of the document.
- p : paste text after cursor position.
- P : paste text before cursor position.
- « : indent the current line to left.
- >> : indent the current line to right.
- o : Start a new line after the current line, this is very useful, especially when you have the filetype indent plugin on, this command will automatically start the new line with the correct indentation under the context.
- O : Start a new line above the current line.
- i : Enter insert mode.
- I : Start editing before the first character on the line.
- a : Append after the cursor, enters insert mode.
- A : Append to the end of line, enters insert mode.
- . : This repeats the last change. This is incredibly powerful, it repeats the last change made.
- @: : This repeats the last command-line command.
- Ctrl-^ : Swaps to the previously edited file. This comes in very handy when swapping between two files back and forth.
- Operators: VIM offers several operators which are all mapped very
logically to the right characters and hence make the commands very easy to
remember. You use operators with motions to form a command.
- Tags: VIM supports tags, a tag is any identifier that is defined in
a special ’tags’ file. Exuberant Ctags is
a utility commonly used to generate these ’tags’ files. Ctags has very god
support for over 41 programming languages. What it does is go through your
entire source code and generate a special ’tags’ file that lists identifiers
found in your code. VIM then uses this for special navigation that allows go
to definition of a function call. The commonly used commands or command-line
commands for working with tags are :
- Ctrl-] : Jump to the definition of the keyword under the cursor. VIM maintains a complete stack of all tags visited as you keep going to the definition of the keywords under cursor one after another.
- Ctrl-t : Jump to the previous entry in the tags stack.
- :tags: This command-line command lists the complete tags stack you have visited, it also marks / highlights your current current location.
- :tag [ident]: Same as Ctrl-] , moves to the definition of [ident].
- :tselect [ident]: Lists the tags that match [ident], useful when there may be multiple matches for a tag.
- :tagnext: Jump to the next matching tag.
- :tagNext / :tagprevious: Jump to the previous matching tag.
- Command-line commands: Most of what I described till now, was done
either in normal mode or the visual mode. There are a lot of things which you
can also do by means of command-line commands which you enter in the bottom of
a screen after type a ‘:’. Most commands also allow you to precede them with
a range, which selects the range in the document on which the command
would work on.
- Range: You may type in one or more line specifiers separated by ‘,’ or
‘;’ before the command. eg.)
:1,10s/.\*//
this deletes all text on lines 1 through 10. These are various options you can use to specify a range :- {number}: an absolute line number to apply the command-line to only that line. You can also give {number1,number2} to specify a range of line numbers and then the command-line would be executed in those lines.
- .: the current line.
- $: the last line of the document.
- %: the entire document. Same as 1,$
- ’m: the position of mark m, you can also use a range
'm1,'m2
to specify a range. A commonly used range I mentioned above is'<,'>
which selects the last visual selection. - /: position of the next search match.
- ?: position of the previous search match.
- /{pattern}: you can even use use the search as a range, except the command will be applied onto only the next line with the pattern match.
- ?{pattern}: same as /{pattern} range but backwards.
- A few basic command-lines that are handy for daily basis:
- :new / :edit file: open a new blank file or a file for editing, the nice thing is that executing this command without the file option will reload the current file from the filesystem.
- :write: short for write, this writes the changes to the file to disk, or essentially saves the file.
- :quit: short for quit, it quites the current buffer if there are no unsaved edits. If you execute this on the last buffer it quits vim.
- :wq: writes the file to disk and quits.
- :s/{pattern}/{string}/[flags]: VIM’s search and replace is as neat
as the search itself. The same rules apply to the {pattern} while search
and replace.
:s/{pattern}/{string}
will replace the match {pattern} with {string}. One of the very lesser known and amazing facts about this is that you can use any single byte character as the delimiter to separate the {pattern} & the {string}. It can be helpful at times especially when there are ‘/’ in the pattern, instead of escaping them, it’s easier using a different delimiter altogether. eg.):%s#/home/dhruvasagar#/Users/dhruva#
. Most commonly used flags are :- &: to reuse the flags of the last search & replace command-line.
- g: to match multiple patterns in same line.
- c: confirm each substitution, is useful when you are not very sure about your {pattern}.
- i: ignore case for {pattern}, this ignores the ‘ignorecase’ / ‘smartcase’ options.
- I: don’t ignore case for {pattern}.
- n: report the number of matches, this is very useful for counting the total number of matches for your {pattern}, the matches are not substituted in this case, only counted.
- :grep: This is an interface to the most commonly used command line utility ‘grep’. I use this on a daily basis to search for patterns across multiple files inside my codebase. This builds a quickfix list which you can see using :copen and traverse using :cnext, :cprevious commands. If you use tpope’s plugin Vim Unimpaired it provides some really nice mappings for such basic traversals. For quickfix list navigation you can use [Q , [q , ]q & ]Q for going to the first item, previous item, next item & last item in the quickfix list. Vim also offers :vimgrep, a native implementation of grep which can be useful, especially on platforms where grep is not available, although in general practice I have found it to be too slow for my liking.
- Range: You may type in one or more line specifiers separated by ‘,’ or
‘;’ before the command. eg.)
- Registers: VIM has a notion of registers, think of them as placeholders or variables. When you execute normal mode or visual mode commands, you can optionally precede them with “{a-z} . For example, you can say “ayy this command will copy the current line (yy) into the register a . You may then use the register value to paste using “ap to paste the value of register a after the cursor. This allows you to be able to save different things in different registers and hence takes the notion of clipboard to the next level allowing you to have multiple named clipboards. You can refer to the actual system clipboard by the special register + . Registers may also be used to store macros, which I will describe later.
- Insert Mode Completion: VIM has an amazing insert mode completion
system, even better than what most IDE’s provide, at least in my
opinion. The various completions I use on a daily basis are :
- Ctrl-n / Ctrl-p : this is the most commonly used completion that works most of the time. It completes keywords from ‘complete’ option, often plugins will update this option based on the file types so it’s usually quite sensible. It will open up a completion menu with a list of various completions to the word that are relevant, you can use Ctrl-n also to navigate to the next possible completion in the list or Ctrl-p to go to the previous option in the list. <Esc> will close the completion menu and bring you back to normal mode.
- Ctrl-x + Ctrl-n : This completes keywords only from the current file.
- Ctrl-x + Ctrl-l : This completes whole lines, very useful!
- Ctrl-x + Ctrl-k : VIM allows you to set a ‘dictionary’ option, eg.) set dictionary=/usr/share/dict/words is what I have set it to, works on both linux (ubuntu) and mac osx. This completes word matches from the dictionary.
- Ctrl-x + Ctrl-t : VIM also allows you to set a ’thesaurus’ option. This completes words from the thesaurus!
- Ctrl-x + Ctrl-i : This completes keywords from the current & included files.
- Ctrl-x + Ctrl-] : This completes keywords from tags.
- Ctrl-x + Ctrl-f : This completes keywords from the file system, comes in very useful while writing file names or paths.
- Ctrl-x + Ctrl-o : This is called omni complete, is generally defined by various language plugins and allows for ‘context aware’ completion. This tries to guess what item exists before the cursor and tries to complete based on that. A common example is method completion for an object.
- Ctrl-x + s : This completes with suggestions for spelling if you turn on the spell checker.
- Macros: Another incredibly powerful feature in VIM is to be able to record complex changes into registers, known as macros. You can create intelligent macros and then apply them to other similar text. eg.) Change a ruby symbol :string to ‘string’, note ‘string’ could be any value, although this is quite a trivial example and I would most likely do this change with search and replace, but I am using it for the purpose of explaining the usage of macros. You could go to the first character ‘:’, then press qa to start recording the macros into the register a . then type r’ea’<Esc> - and then press q again to stop recording. Now you could go to the first character of any Ruby symbol and execute the macros using the @a command. Which will repeat the macro recorded into the register a . Although this is a trivial example, a lot can be achieved using macros. You can even create recursive macros in creative ways to repeat complex changes recursively to a document for all changes by including macro execution or searches within the macro itself.
- Splits: One of the killer features (IMO) is the ability to be able to
create splits, both vertical and horizontal. While programming, it is rare
that we work only on a single file. Almost always we work through a series of
files with complex code. Splits allow you to be able to open multiple files
simultaneously within the same screen. Each split is called a window. Some
common shortcuts / command-line for working with splits are :
- Ctrl-w + c
: Close a window. This is the same in effect
as typing the command-line
:q
in that split. - Ctrl-w + v
: Create a new vertical split and opens the
current file in both splits, you can then use the
:e
file command to open another file. You can do the same using the command-line:vsplit
file to open file into the new vertical split or the same as Ctrl-w + v without specifying a file. - Ctrl-w + s : Create a new horizontal split.
- Ctrl-w + w / Ctrl-w + Ctrl-w : This moves your cursor to the next split in the window, you can cycle through all splits by repeating this.
- Ctrl-w + h : Move cursor to the window on the left. Depending on the cursor location VIM will select the split that is left of the current and move your cursor.
- Ctrl-w + l : Move cursor to the window on the right.
- Ctrl-w + j : Move cursor to the window below.
- Ctrl-w + k : Move the cursor to the window above.
- Ctrl-w + H : Move the current split window to the extreme left and occupy the entire height.
- Ctrl-w + L : Move the current split window to the extreme right.
- Ctrl-w + J : Move the current split window to the absolute bottom and occupy the entire width.
- Ctrl-w + K : Move the current split window to the absolute top.
- Ctrl-w + c
: Close a window. This is the same in effect
as typing the command-line
- Tabs: VIM also supports tabs, if splits don’t work for you, you can open
documents in separate tabs to utilize the full screen space. You can use the
follow command-line for working with tabs :
- :tabnew / :tabedit: Same as :new / :edit, except it opens a new tab or the input file in a new tab.
- :tabnext: Move to the next tab.
- :tabprevious / :tabNext: Move to the previous tab.
- :tabclose: Close the current tab, this is helpful when you have multiple splits in a single tab and you want to close them all at once.
- :tabonly: Close all other tabs.
- :tabfirst: Go to the first tab.
- :tablast: Go to the last tab.
- :tabmove [N]: to move the current tab after tab page N.
- Diff: Another incredibly powerful feature of VIM is it’s ability to diff between files and very easily resolve conflicts. VIM allows not only for 2 way, but n way diffs :), although I haven’t used more than a 3 way diff but the fact that it’s possible surely speaks volumes. You can use ]c and [c to navigate to the next and previous conflict respectively. You can use do (read as diff obtain) to get the other document changes to resolve conflict and dp (diff put) to put the current document changes into the other document to resolve conflict. Note the commands do and dp work only in case of a 2 way diff since in multiple diffs it is not clear which buffer to obtain or put diffs from. You can use the command-line :diffget and :diffput in the same way, with an optional pattern to match the source / target buffer.
- Plugins: VIM provides a scripting language called ‘vimscript’, which one
can use to program and extend various elements of VIM. VIM has an amazing
vibrant community and given how long VIM has been around and how popular it
has been, there has been a lot of plugins contributed by the community. You
can find them here : http://www.vim.org/scripts/index.php. Few of the
plugins I use and can’t live without are :
- Command-T: Quickly open files
- VIM Endwise: Automatically add ’end’ intelligently after if, do, def, etc to complete the blocks in ruby
- Vim Fugitive: Awesome Git wrapper for VIM
- Ruby Matchit: Matches ruby blocks with %
- NERDTree: Awesome file system browser
- [NERDCommenter]https://github.com/scrooloose/nerdcommenter): Makes commenting multiple lines in many programming languages a breeze.
- VIM Pathogen: For managing plugins.
- VIM Powerline: VIM status line on steriods.
- VIM Rails: One of the most amazing plugins written by none other than Tim Pope
- VIM Ruby: VIM plugins for Ruby.
- VIM Ruby Debugger: For debugging Ruby scripts or Rails projects like an IDE with complex breakpoints, step execution, runtime variable values lookup, etc.
- SnipMate: Inspired from Textmate bundles, provides really neat insert mode auto completion.
- VIM Surround: Makes adding, changing and deleting quotes around text very easy.
- Syntastic: Automatic syntax checking for various programming / scripting languages, provides errors and warnings with visual indications using signs.
- VIM Unimpaired: Another Tim Pope’s plugin, mentioned above as well, provides several logical bracket mappings.
- Tabular: Really nice for formatting and aligning texts on multiple lines.
This post has gotten much longer than I would have liked, there might even be a few mistakes here and there, but it goes to show how much there is that you can do with VIM. I tried to cover as much as I know, but this just scratches the surface, hopefully this will give you the platform that you can use to launch yourself into VIMdom without fears and appreciate VIM in a way that I have come to over the years.
You can find my vim directory at My ~/.vim directory for reference. Although I must warn you that mine is quite a huge one loaded with lots of plugins, complex configurations in vimrc and I update my repo very frequently, so try it at your own risk ;).