This is doable, though quite complicated. Here's how.
Step 1. Having ^M
in a mapping does not work, it is treated as if you hit <CR>
, which would execute the :call
command which is not yet complete. To make it work we need to replace it with something which is not interpreted as an Enter hit -- e.g. \n
:
nnoremap <localleader>a :call <sid>Test({'cmd':"Hello\nWorld"})<cr>
Note: the string has to be double-quoted, otherwise \n
is treated as two characters instead of one ^M
character.
Step 2. s:Test
tries to convert this to a string and pass on to another mapping command. The mapping is successfully created, but when run -- has the same problem as in step 1 above -- object when converted to string has ^M
in it, which is treated as a <cr>
hit, and executes the :call
command. This time we have no luxury of replacing with \n
. But we're within a function now and can do other tricks. For example, we can now save this object to some script-variable:
let s:tab_argument = a:obj
This can now be used instead of a:obj
in the mapping. Also, since we don't have anything variable now, we can omit execute
and define mapping directly:
inoremap <silent> <tab> <esc>:<c-u>call <sid>Test2(<sid>tab_argument)<cr>
Step 3. Unfortunately, :map
does not seem to be able to understand script-local variables. Let's work around this by defining another function with no arguments:
function! s:tab_lambda()
call s:Test2(s:tab_argument)
endfunction
Step 4.
Now let's put this all together:
function! s:Test(obj)
let s:tab_argument = a:obj
function! s:tab_lambda()
call s:Test2(s:tab_argument)
endfunction
inoremap <silent> <tab> <esc>:<c-u>call <sid>tab_lambda()<cr>
endfunction
function! s:Test2(obj)
" do something
endfunction
nnoremap <localleader>a :call <sid>Test({'cmd':"Hello\nWorld"})<cr>
Note: I may be stating obvious, but make sure you don't have local <tab>
mappings. If you do, inoremap
will succeed, but hitting <tab>
won't call the Test2
function.
\r
,\<CR>
,<lt>CR>
as well