By default, C-o
allows to execute a normal command from insert mode. Example:
foo bar| baz
^ represents the cursor
The current mode being insert mode, and the cursor being after the word bar
, to delete the next word, you could hit C-o daw
.
However there are several ways to enter insert mode. Most of the time (i
, a
, o
, O
, ...), C-o
will behave as expected. However, if you enter insert mode from visual mode, for example by pressing A
from visual block mode (:h v_b_A
), its behavior depends on whether you've already inserted text, and the number of times you pressed it.
Example:
foo bar| baz
If you press:
C-v
to enter visual block modeA
to enter insert modeC-o
to enter normal modedaw
to deletebaz
... daw
is literally inserted into the buffer:
If you repeat the same sequence of keys, but this time you repeat C-o
a 2nd time:
C-v A C-o C-o daw
C-o
behaves as expected:
There's a third behavior which requires a multi-line text to be observed:
foo | baz
foo baz
Suppose you want to add bar
between the foo
and baz
on the 2 lines.
The cursor being between foo
and baz
on the 1st line, you can press:
C-v
to enter visual block modej
to go down one lineA
to enter insert modebar
to insertbar
If you press Escape
, you'll get:
foo bar baz
foo bar baz
Now suppose you don't press Escape
, because before going back to normal mode, you want to delete the next word baz
. You could press C-o daw
, expecting the following buffer:
foo bar
foo bar
But that's not what you'll get, instead you'll have:
foo daw bar baz
foo bar baz
What happened is that when you pressed C-o
, Vim reinserted the text you had typed (here bar
) at the end of each line of the visual block, and moved the cursor to the upper left corner of the block. In other words, it's as if you had pressed Escape
then i
.
C-o
is often used in an insert mode mapping. Here's an example:
ino <c-x><c-k> <c-o>:exe 'setl dict='
\. (&l:spelllang ==# 'en'
\? '/usr/share/dict/words'
\: '/usr/share/dict/ngerman')
\<cr><c-x><c-k>
This mapping customizes the default dictionary completion C-x C-k
.
It first checks the buffer-local value of the 'spelllang'
option. If it's en
, then the mapping sets the buffer-local option dict
to /usr/share/dict/words
(dictionary for english words), otherwise to /usr/share/dict/ngerman
(dictionary to german words). Then, it performs the usual dictionary completion.
It works as long as you've entered insert mode from normal mode. But if you entered insert mode from visual mode, instead of completing the text looking into a dictionary, it dumps the {rhs}
of the mapping inside the buffer.
Because of this, I never use C-o
in a mapping because I don't know how to detect what was the previous mode, before insert mode.
Instead I use C-r =
:
ino <c-x><c-k> <c-r>=<sid>set_dict()<cr><c-x><c-k>
fu! s:set_dict() abort
exe 'setl dict='.(&l:spelllang ==# 'en' ? '/usr/share/dict/words' : '/usr/share/dict/ngerman')
return ''
endfu
This solves the issue for a mapping. But in an interactive use, sometimes you have to hit C-o
once, and sometimes twice.
Is it possible to make i_C-o
unaffected by the mode from which we entered insert mode?
vim -Nu NONE
). I added a gif to illustrate.-- INSERT --
should change to-- (insert) --
to indicate you are in normal mode falling back to insert mode. I am on version 8.987.