0

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.

0

1 Answer 1

0

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
endfunction

Then

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

Becomes

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.

2
  • 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, 2017 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, 2017 at 18:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .