What is the best way to specify multiple modes for a map in vim?

I know that nmap x y triggers y on receiving x when in normal mode,

imap x y triggers y on receiving x when in insert mode, and so on.

Say I specifically want those two modes. Then I can not use map x y.

Just writing two lines produces a lot of clutter when done for multiple mappings.


From :h mapmode-n:

There are six sets of mappings

  • For Normal mode: When typing commands.
  • For Visual mode: When typing commands while the Visual area is highlighted.
  • For Select mode: like Visual mode but typing text replaces the selection.
  • For Operator-pending mode: When an operator is pending (after "d", "y", "c", etc.). See below: |omap-info|.
  • For Insert mode. These are also used in Replace mode.
  • For Command-line mode: When entering a ":" or "/" command.

There are many different ways to make a mapping. If you :h map, you will see which modes the various commands map modes for:

:map    {lhs} {rhs}     |mapmode-nvo|       *:map*
:nm[ap] {lhs} {rhs}     |mapmode-n|     *:nm* *:nmap*
:vm[ap] {lhs} {rhs}     |mapmode-v|     *:vm* *:vmap*
:xm[ap] {lhs} {rhs}     |mapmode-x|     *:xm* *:xmap*
:smap   {lhs} {rhs}     |mapmode-s|         *:smap*
:om[ap] {lhs} {rhs}     |mapmode-o|     *:om* *:omap*
:map!   {lhs} {rhs}     |mapmode-ic|        *:map!*
:im[ap] {lhs} {rhs}     |mapmode-i|     *:im* *:imap*
:lm[ap] {lhs} {rhs}     |mapmode-l|     *:lm* *:lmap*
:cm[ap] {lhs} {rhs}     |mapmode-c|     *:cm* *:cmap*

As you can see, :map says mapmode-nvo, which stands for normal, visual, and operator-pending mode. That is the reason that map x y does not work in normal mode. Looking through this list, you can see how none of them have mapmode-in, so there is no one way to do this. So you will need to do nmap x y and imap x y. Or if you want it to apply to every mode, map x y, and map! x y.

Just writing two lines produces a lot of clutter when done for multiple mappings.

If you're really doing lots of mappings, you could do this:

function! DoubleMap(x, y)
  exec "nmap ".x." ".y
  exec "imap ".x." ".y


imap x y
nmap x y
imap foo bar
nmap foo bar
imap blah spam
nmap blah spam


call DoubleMap('x', 'y')
call DoubleMap('foo', 'bar')
call DoubleMap('blah', 'spam')

But this will be a pain if your mapping has quotes or unprintable characters.

  • Thank you for this detailed answer. Too bad that there exists no mapmode for this combination. It seems like I will have to learn more about vimscript in general at this point. Using a function seems like a good option for simple binds. – omnesia Aug 2 '17 at 18:44
  • @omnesia Glad I could help! :) BTW, there is also a vi & vim site that is generally better for vim-specific questions. – DJMcMayhem Aug 2 '17 at 18:52

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.