I'm trying to toggle some ctrl maps in command directly, it didn't work as expected:

com Test0 nnoremap <c-j> :echo "c-j"<cr>
com Test1 nnoremap <c-h> :echo "c-h"<cr>
com Test2 exe 'nnoremap <c-l> :echo "c-l"<cr>'
com Test3 exe 'nnoremap <c-right> :echo "c-right"<cr>'

" uncomment this, I see results of :map and "E15: invalid expression: ^M"
" Test0

Only Test1 and Test2 works. Test0 works like :map, have no idea why that happens. If I execute the exe ... or nnoremap ... sub command in command line, everything works. what am I missing?

  • My general advice (also in 'autocmd's) is to avoid all substitution and quoting pitfalls by having your command just call a function and have the function execute all the commands, which means the commands will all run in a sane context where you know what to expect. Also, bonus: you get to add more commands to the function easily rather than having to deal with | and <bar> etc. (essentially one more variation of the same problem.)
    – filbranden
    Mar 25, 2020 at 14:26
  • @filbranden One size does not fit all. There are times the sub command took only one or two statements. I believe one should not write function in that case, especially when that function is only called by this command alone.
    – dedowsdi
    Mar 25, 2020 at 23:16

1 Answer 1


Hmm. This is interesting. Here's what get saved as the command (:com Test0):

nnoremap <NL> :echom "c-j"<CR>

(<C-J> is equivalent to <NL> in Vim)

So what do we know about the <> format? That it can be used in mappings and abbreviations as a substitute for the represented keys/chars. That it can be used in exe command arguments the same way but only if escaped (e.g. \<Tab>).

If that command is entered directly it works. It would make sense that it should do the same when run by the operation generated by com. But it doesn't. Instead the <NL> is acting like Enter key and when Test0 is run it submits the nnoremap alone, immediately. And, actually, we can't assume that something executed indirectly follows the exact same documented behavior as for the directly entered equivalent and obviously it's not here.

Without diving into the code (which I might just do) I can only surmise. There is something that makes <NL> different from other key(codes). Along with <CR> it is the only thing that can submit commands for execution (:h c_<NL>: "start entered command"). I'd assume that's a crucial detail here with respect to why other special keycodes (e.g. <c-h>) don't behave differently than expected. Note that if you skim through the results of, for example, :helpgrep <NL> you'll see there are various places where <CR> and <NL> have exceptional behavior and/or are treated differently than most other special characters. So I don't think what we're seeing here, while a head-scratcher, is totally unexpected or unprecedented.

Anyways, for now I at least can offer a working version. This successfully escapes the mapped key...

com! Test0 exe 'nnoremap \<c-j> :echom "c-j"<cr>'

Funny things is, this just adds to the mystery, really. Now we're sort of doing double indirection/interpretation and it works the way we'd expect! Interesting.

  • Thanks. I thought keycodes only have special meaning in map family commands, I must be wrong. Could you point me where can I find keycode have special meaning in command in help?
    – dedowsdi
    Mar 25, 2020 at 3:32
  • There is also :h c_CTRL-H and :h c_CTRL-L, why would Test1 and Test2 work? <c-right> also have special meaning in command line mode.
    – dedowsdi
    Mar 25, 2020 at 3:39
  • Yeah...the order things are happening is a little different than what I said I believe...updating my answer
    – B Layer
    Mar 25, 2020 at 4:25
  • Alas, I retracted my definitive analysis for something less satisfying. :)
    – B Layer
    Mar 25, 2020 at 4:52
  • 1
    Thanks for the digging. It's the first time I see the valid use of \<c-..> in single qutoe, it's so hard to swallow. Another work around is com! Test0 nnoremap <lt>c-j> :echom "c-j"<cr>.
    – dedowsdi
    Mar 25, 2020 at 5:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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