5

I'm testing NeoVim and would like to put in my vimrc universal mapping for either vim and nvim.

I've sketch sth like below so far, but it doesn't work and it's very rough.

function! Meta(key) " define if using alt(it works in neovim) or leader key. Used below for mapping only.
    " for neovim testing and changing habits
    if has('nvim')
        let meta = "<A-" . a:key . ">"
    else
        let meta = "<leader>" . a:key
    endif
    " return meta
endfunction

call Meta('j')
nnoremap <silent>meta :set paste<CR>m`o<Esc>``:set nopaste<CR>
call Meta('k')
nnoremap <silent>meta :set paste<CR>m`O<Esc>``:set nopaste<CR>
(...)

How to solve it in a smart way?

2 Answers 2

10

The :map command takes :help key-notation, but not variables. Vimscript is evaluated exactly like the Ex commands typed in the : command-line. There were no variables in ex, so there's no way to specify them. When typing a command interactively, you'd probably use <C-R>= to insert variable contents:

:sleep <C-R>=timetowait<CR>m<CR>

... but in a script, :execute must be used. All the literal parts of the Ex command must be quoted (single or double quotes), and then concatenated with the variables:

execute 'sleep' timetowait . 'm'

Your example

Here's the variable interpolation applied to your example (using a script-local variable):

function! Meta(key) " define if using alt(it works in neovim) or leader key. Used below for mapping only.
    if has('nvim')
        let s:meta = "<A-" . a:key . ">"
    else
        let s:meta = "<leader>" . a:key
    endif
endfunction

call Meta('j')
execute 'nnoremap <silent>' . s:meta . ' :set paste<CR>m`o<Esc>``:set nopaste<CR>'

However, I would change your function to return the resulting key, so that you save the separate function invocation and variable:

function! Meta(key) " define if using alt(it works in neovim) or leader key.
    " for neovim testing and changing habits
    if has('nvim')
        return "<A-" . a:key . ">"
    else
        return "<leader>" . a:key
    endif
endfunction

execute 'nnoremap <silent>' . Meta('j') . ' :set paste<CR>m`o<Esc>``:set nopaste<CR>'
execute 'nnoremap <silent>' . Meta('k') . ' :set paste<CR>m`O<Esc>``:set nopaste<CR>'
2
  • i think ur missing a fullstop in execute 'sleep' timetowait . 'm'
    – john-jones
    Commented Oct 11, 2022 at 11:05
  • @john-jones: No, :execute will concatenate multiple arguments (with whitespace in between - notice how else I would also missing a whitespace, too). But yes, you can also write it execute 'sleep ' . timetowait . 'm' if you'd like! Commented Oct 11, 2022 at 12:08
3

On complement to @Ingo's answer which explains very well how it could be done. If you need to define many mappings, I'd go with defining a dedicated command to write things like

Meta nnoremap <silent> j :set paste<cr>m`o<esc>``:set nopaste<cr>

Which could be defined thanks to

" TODO: add support for command line completion...
command! -nargs=+
      \ Meta
      \ call s:Map(<f-args>)

let s:is_meta_supported = has('nvim') || has('gui_running')

function! s:Map(how, ...)
  let cmd = a:how
  let is_key_known = 0
  for a in a:000
    if ! is_key_known && a !~ '^<\k\+>$'
      let cmd .= s:is_meta_supported ? ' <M-'.a.'>' : ' <leader>'.a
      let is_key_known = 1
    else
      let cmd .= ' '.a
    endif
  endfor
  exe cmd
endfunction

Side note: meta keys (usually bound to <M-) works well (enough) with gvim as well -- it's just that gvim doesn't make any difference between <m-i> and é, and many other diacritics.

3
  • wow. U're fast plugin maker :) There is so many magic tricks for me - I will stay in simple function approach until learn more vim lang. Then turn back to ur solution and a plugin template (seems solid). Anyway - thanks!
    – Mesco
    Commented Nov 18, 2016 at 17:14
  • and yes, ur right - meta in vim works fine (i don't need left alt utf characters like é). For some reason I have had troubles with it earlier, and solve it when meet similar problems with nvim now (xterm escape character that is used in ALT as well combined with timux timeout).
    – Mesco
    Commented Nov 18, 2016 at 17:22
  • It's just that I have a few plugins that do similar things (X) and that I've been updating/upgrading them lately. (X) Like defining mappings and menus with only one command call, or defining context sensitive abbreviations and mappings that don't expand within comment or string contexts. Commented Nov 18, 2016 at 17:38

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.