One of the first things you learn when starting using vim is that you spend a lot of time in the normal mode, and that’s where all the interesting actions happen. Insert mode is there just for inserting literal text.
Well, that’s only part of the story. There are actually some quite interesting things you can do while in insert mode.
This post is about those things.
There is one feature that most users already know: autocompletion. I will leave it as a separate topic, and also, I think it’s pretty well covered in other places already.
- Iabbrev
- imap
- <C-o>
- <C-R>
- Surprising ways to use iabbrev and imap
- Picking ergonomic mappings
- More examples
iabbrev
Iabbrev is a feature that expands abbreviation.
For example, you might want to have this In your vimdc:
iabrev mmm milosz.danczak@sidebits.tech
And now, whenever you type “mmm” and then any character other than a letter or number (like a space, or a dot), “mmm” will be replaced with “milosz.danczak@sidebits.tech”.
If there are any characters right before the abbreviation, it will prevent the replacement from happening.
So, if you type “ommm”, it will not be replaced.
Iabbrev can be used not only for convenient phrases. It can be used for fixing typos you are prone to make. For example, I tend to misspell “daemon” as “deamon”. So I can put this in my .vimrc:
Iabbrev deamon daemon
Now, if I misspell it, vim will correct it for me.
I have one problem with this approach, though: I might not even notice that I made a typo, and vim can spoil me to never have to learn to type the word correctly. However, I can make vim force me to correct the misspelling myself, so that I learn to spell the word correctly:
iabbrev deamon dAEmon TYPO!!!
Now if I misspell it, it will be replaced with “dAEmon TYPO!!!”, so I can see it and correct it manually, thus breaking my bad habit.
If you use iabbrev this way , you might want to check out vim-abolish. It provides a way to conveniently create abbreviations for multiple variants of words.
imap
imap establishes mappings for insert mode.
You might have used its more popular cousin, nmap.
imap, just as iabbrev, is a way to make vim do something when you type something in the insert mode – but it is more general.
Let’s look at some examples.
Note about the examples: I’m using the “nore” variant of imap, i.e., inoremap, to avoid recursive mappings. It’s almost always what you want.
You can have a mapping that will simulate pressing the Escape key, in order to get back to the normal mode:
inoremap ji <esc>
Now you can exit the insert mode without reaching for the Escape key!
You can have a mapping to exit the insert mode, save the buffer, and return to the insert mode:
inoremap ,.s <esc>:w<cr>a
The main difference from iabbrev is that imap doesn’t care about the word boundaries. iabbrev foo bar
will ignore “xfoo” or “foox”; but imap foo bar
will replace “xfoo” with “xbar”. Also, imap does not wait until you enter any other keys after the key sequence you mapped.
It gives you more freedom, but you need to be more careful with avoiding key sequences that you might want to insert.
For example, if you would do this mapping:
inoremap ing ANYTHING
…you just locked yourself out from inserting any word that includes “ing”!
If you end up in a situation where you need to bypass a mapping, you can do one of 2 things:
- Run “:iunmap <key sequence>” (in our example, it would be “:iunmap ing”). It will remove the mapping until you start vim again.
- Press Ctrl-V before the sequence. It forces the next character to be inserted literally, bypassing any mappings (it doesn’t have anything to do with Windows shortcut for pasting).
Finding good candidates for imap and iabbrev
List of 3-character sequences that don’t occur in the English dictionary (at least the one I had installed on my linux box).
It’s over 11 000 potential mappings! You won’t run out of good mappings.
You might want to take any other languages you use into account. If you want to compose your own list, you can use my hacky script.
I recommend picking sequences which don’t require the same finger to be twice in a row; e.g., “jjj” and “jmu” are bad; “dhf” and “dfs” are good (assuming QWERTY layout).
Ctrl-O
When in insert mode, Ctrl-o will allow you to perform a single normal mode operation.
Note that a single operation does not always mean a single key. “j”, “dd”, and “:w!” are some examples where each counts as a single operation, and can be done from Ctrl-o.
You can read more in vim’s help system: :help i_CTRL-O
.
Ctrl-R
When in insert mode, pressing Ctrl-r and a register name will put the content of that register at the cursor.
You can read more in vim’s help system: :help i_CTRL-R
.
More examples
Special characters
My native language has letters that are not ASCII, which sometimes is a problem if the computer I happen to be using doesn’t have input methods set for me.
I can use imap to have a convienient shortcut for inserting the problematic characters:
inoremap <C-y>o ó
(You can use it also with digraphs, but that’s another topic)
Filetype-specific mappings and abbreviations
You can combine imap and iabbrev with autocommands to have filetype-specific mappings and abbreviations.
Here, I’m setting <C-L> to be translated to ” => ” in several programming languages where it’s used, and setting an abbreviation of “ret” to “return”:
augroup PROGRAMMING
autocmd!
autocmd FileType javascript,php,ruby inoremap <buffer> <C-L> <space>=><space>
autocmd FileType javascript,python iabbrev <buffer> ret return
augroup END
<buffer> makes the mapping or abbreviation local to the current buffer.
Insert current date
I use this one a lot. “dst” will be replaced today’s date:
iabbrev <silent> dst <C-R>=strftime("%Y-%m-%d")<cr>
It takes advantage of <C-R>= to run a vim function, strftime.
Current file name
Insert current file’s name, without extension. I find it useful in codebases when the convention of naming classes has to be consistent with filenames (e.g., “SomeThing.java” contains class “SomeThing”).
iabbrev <silent> crr <C-R>=expand('%:t:r')<cr>
Insert result of external command
This allows to insert output of any UNIX command, without ever exiting insert mode.
function! ExternalCommandResult()
return system(input('Command: '))[:-2]
endfunction
inoremap <C-R>! <C-R>=ExternalCommandResult()<cr>
Now try <C-R>!, then type “date”, and press Enter.