5

I'd like to define my own operator. Vim's builtin help has a nice little tutorial on it, where they show you can create your own operator with opfunc and g@:

nmap <silent> <F4> :set opfunc=CountSpaces<CR>g@
vmap <silent> <F4> :<C-U>call CountSpaces(visualmode(), 1)<CR>

function! CountSpaces(type, ...)
  ...
endfunction

There's only one downside to this approach. Let's say for example, that I want to run <F4>2j. That works fine, but 2<F4>j does not. This gives

E481: No range allowed

This makes perfect sense because the range is applied to the set opfunc command, not the g@ command.

I thought that I would be able to get around it by doing this:

nnoremap <expr> <F4> ":\<C-u>set opfunc=Test\<cr>".v:count1.'g@'

But when I run this, it causes some strange issues where '[ and '] are incorrectly defined in the function. (I'd be happy to go into more details in chat, but that's unrelated to my question. I've reproduced this bug in Vim 8.0 on Windows and Ubuntu and in Neovim 0.2.1 on Windows)

So how can I define my operator so that a count works the same before or after the operator? I realize that this is a very minor difference, and that for most intents and purposes, I can simply get around it by always doing the count afterwards. But vim's default operators work this way, and I would really like mine too also.

9

You can call a function transparently within a mapping, thus circumventing mode changes (e.g. by pressing :) or losing counts, by using <expr> mappings, similar to what you suggested. Just use them to call a function like so:

fun! SetOpFunc()
    set opfunc=CountSpaces
    return 'g@'
endfun
nno <expr> <F4> SetOpFunc()

This technique isn't limited to operator mappings either. For example I've used it in Operator-pending mappings to call a function during the mapping without disrupting modes or counts, returning '' at the end. This way you can leverage Vim's native features rather than having to recreate them yourself.

  • Fantastic! This does exactly what I want, thankyou very much! – DJMcMayhem Jun 4 '17 at 22:28

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.