5

Say that I have some semi-complex keymaps like the following:

nnoremap <Leader>s :%s/\s\+$//e
nnoremap <Leader>u mz:r!uuidgen<CR>dW"_dd`zp"
nnoremap <Leader>d g/\v"([^"]|\n)*"\ze\n\s*\[.*\]/normal gngq

In general, how does one translate an arbitrary keymap to a VimL function?

The following does not work:

function! Trim()
  normal mz:%s/\s\+$//e<cr>`z
endfunction
command! Trim call Trim()

function! UUID()
  normal mz:r!uuidgen<CR>dW"_dd`zp
endfunction
command! UUID call UUID()

function! FormatClojureDocStrings()
  normal mz:g/\v"([^"]|\n)*"\ze\n\s*\[.*\]/normal gngq<cr>`z
endfunction
command! FormatClojureDocStrings call FormatClojureDocStrings()
3

This is because special keys like <esc> are not translated to their actual meaning in normal commands. Thus, normal <esc> translates to literally typing less-than e s c greater-than. You can get around this by doing something like this:

execute "normal <esc>"

In your case, it would look like this:

function! Trim()
  execute "normal mz:%s/\s\+$//e<cr>`z"
endfunction
command! Trim call Trim()

function! UUID()
  execute "normal mz:r!uuidgen<CR>dW\"_dd`zp"
endfunction
command! UUID call UUID()

function! FormatClojureDocStrings()
  execute "normal mz:g/\v\"([^\"]|\n)*\"\ze\n\s*\[.*\]/normal gngq<cr>`z"
endfunction
command! FormatClojureDocStrings call FormatClojureDocStrings()

Note that these special keys will only be translated if they are in double quotes.

2
  • Do the quotes inside of the execute strings need to be escaped? – user489 Feb 25 '15 at 5:38
  • Yes they do, forgot to include that. – EvergreenTree Feb 25 '15 at 11:40
4

Typically you divide your commands up into 3 categories:

  • Normal commands that need to run via :normal/:normal!
  • Ex-commands which can be run without the leading :
  • Commands that need to "built up" use execute. e.g. execute "s/" . pat . "/". rep . "/g". (This is actually just a specialization of the previous rule)

Lets take a do a quick-n-dirty attempt at your UUID command:

command! UUID call s:uuid()
function s:uuid()
  normal! mz
  r!uuidgen
  normal! dW"_dd`zp
endfunction

Now we have a few issues with this:

  • We are mutating the z mark and the unnamed register so this may cause surprises. The typical solution is to save the register and restore the register later in the function
  • Ex-commands typically do things linewise so this command is a bit out of the ordinary. (This may be better as a mapping <c-r><c-u> perhaps)

Fixing/side-stepping the mutation issues by using the expression register, "=, and the system() function.

command! UUID execute "normal! a\<c-r>=substitute(system('uuidgen'), '\\n', '', '')\<cr>\<esc>"

For more help see:

:h :normal
:h :execute
:h i_ctrl-r
:h system(

You may also want to look at Steve Losh's Learn Vimscript the Hard Way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy