Working on a more lightweight vim-endwise replacement (endwise breaks imap <expr> <CR> mappings).

In the following text:

def name<-cursor here

it adds a newline and another line with an end:

def name
  <-cursor here

This mapping does the job:

autocmd FileType ruby inoremap <buffer> <expr> <CR> match(getline('.'), 'def') >= 0 ? '<CR><CR>end<Esc>-cc' : '<CR>'

However, I'd like to extend this to also understand if, case and do, but the following does not work:

autocmd FileType ruby inoremap <buffer> <expr> <CR> match(getline('.'), 'def\|if\|case\|do') >= 0 ? '<CR><CR>end<Esc>-cc' : '<CR>'

Even though match(" case abc", 'def\|if\|case\|do') >= 0 returns 1 (e.g. true).

What am I doing wrong?

  • Extracting to a function does not make things easier: '\<CR>' returns text, not a newline, an unescaped '<CR>' errors out, even though match seems to work properly. Nov 9, 2016 at 13:31
  • 2
    Do yourself a favor and put that into a normal ftplugin and simply call a function for that filetype. Then you don't have to worry about escaping all possible metachars and even better 2 days from today, you still understand what you are doing ;) Nov 9, 2016 at 17:13
  • @ChristianBrabandt moved everything to a ftplugin, but still have to double escape | Nov 9, 2016 at 20:27
  • @philpirozhkov There is another advice in Christian's comment: define a function. This way your regex will be simplified, and much easier to maintain. Nov 9, 2016 at 22:58
  • @LucHermitte See above, in a function output needs to be escaped, e.g. '<CR>' does not work, nor '\<CR>' does, I've seen people use ""<CR' and '\<lt>CR>', but none of them worked in a function. I'm pretty satisfied with my current solution, will dig deeper when I decide I need to add a closing curly brace when I open one and press CR. Nov 11, 2016 at 16:46

2 Answers 2


IIRC, it's related to the bar character in command lines. You need to escape the bar twice, e.g.:

" ftplugin/ruby/myshortcuts.vim 
inoremap <buffer> <expr> <CR> match(getline('.'), 'if\\|def\\|case\\|do') >= 0 ? '<CR><CR>end<Esc>-cc' : '<CR>

BTW, you should make sure this is exactly def (and not define), that you aren't in string, nor comments.

  • alternatively, you can use <bar>, in place of |, i.e. 'def\<bar>if\<bar>case\<bar>do' worlks
    – nobe4
    Nov 9, 2016 at 13:34
  • autocmd FileType ruby inoremap <expr> <CR> match(getline('.'), 'if\\|def\\|case\\|do') >= 0 ? '<CR><CR>end<Esc>-cc' : '<CR> worked as expected, thanks! Nov 9, 2016 at 13:35
  • @nobe4 it wouldn't have been enough. A backslash is required when there is no magic around (:h /\v) Nov 9, 2016 at 13:42
  • @LucHermitte, Yup, a \<bar> then ? (that's what I've put in the example)
    – nobe4
    Nov 9, 2016 at 13:46
  • 1
    @philpirozhkov. Always. Mappings that make sense only in a restrictive list of filetypes/buffers shall always be declared with <buffer>. Otherwise the next time you open a buffer with a different filetype, the mapping will be defined and could be triggered. Which is not what we want. Nov 9, 2016 at 22:56

Alternatively, you can use <bar> instead of |:

autocmd FileType ruby inoremap <buffer> <expr> <CR> match(getline('.'), 'def\<bar>if\<bar>case\<bar>do') >= 0 ? '<CR><CR>end<Esc>-cc' : '<CR>'

see: :h <bar>

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.