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.


foo bar| baz

If you press:

  • C-v to enter visual block mode
  • A to enter insert mode
  • C-o to enter normal mode
  • daw to delete baz

... daw is literally inserted into the buffer:

enter image description here

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:

enter image description here

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 mode
  • j to go down one line
  • A to enter insert mode
  • bar to insert bar

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')

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 ''

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?

  • Lost you at "... daw is literally inserted into the buffer." That is, I cannot reproduce this. daw works as expected for me. Are you sure you don't have a plugin conflict somewhere? – Mass Sep 1 '17 at 20:47
  • @Mass I don't think it's caused by a plugin conflict, because I can reproduce without them, by starting Vim with a minimum of initializations (vim -Nu NONE). I added a gif to illustrate. – user852573 Sep 1 '17 at 20:52
  • 1
    Odd. What vim version? I did the same experiment as you and one thing I notice different is that -- INSERT -- should change to -- (insert) -- to indicate you are in normal mode falling back to insert mode. I am on version 8.987. – Mass Sep 1 '17 at 20:58
  • 2
    @Mass Yes it solves my issue. If you want to post an answer, I'll accept it. But I just want to find the right commit which fixed the issue. Currently I'm trying to bisect it. If I find it, I'll edit your answer to add the info. – user852573 Sep 1 '17 at 21:18
  • 1
    @Mass Ok I found it, it was fixed in patch 8.0.0282: github.com/vim/vim/commit/… Here's the url of the relevant thread on the issue tracker: github.com/vim/vim/issues/1290 – user852573 Sep 1 '17 at 21:32

This issue, needing to use CTRL-O twice when in visual-insert mode, was fixed in patches 8.0.0282 and 8.0.0291.

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.