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.

| improve this answer | |
  • 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.

| improve this answer | |

Your Answer

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