I want to craft a custom operator-pending motion if for functions in R language that look like this:

doSomething <- function(arg1, arg2, ...) {

The idea is to be able to press yif while on the function body to copy it's contents doStuff(...) in this case. I have something that works:

onoremap if :<c-u>execute "normal! $?<-\\s*function\\s*(\r^/{\r%``j^v``kg_"<cr>

This does the following: searches for the <- function pattern backwards, then finds the first {, jumps to it's match with %, then goes back to the beginning, goes down one line, enters visual mode, jump to the end, goes up one line and finishes.

This works for me with one downside: it finds functions even when I am outside (below) the function body.

My question is: how to make it fail when the cursor is not on a function?

Any other help/tips are appreciated as well.


Following advice from @Luc I wrote a simple function to check if the given line is inside the function:

function! IsInsideRFunction(lnum)
  let currentline = a:lnum
  let savedpos = getpos(".")
  execute "silent! normal! $" . '?<-\s*function\s*(' . "\<cr>"
  execute "silent! normal! " . '/{' . "\<cr>"
  let startline = line(".")
  execute "silent! normal! %"
  let endline = line(".")
  if currentline >=# startline && currentline <=# endline
    call setpos(".", savedpos)
    return 1
  call setpos(".", savedpos)

The function works. However when I put it inside the expression map:

onoremap <expr> aF IsInsideRFunction(line(".")) ? ":echom 'yes'<cr>" : ":echom 'no'<cr>"

it stops working. More precisely - it always returns "1".

What am I doing wrong?

1 Answer 1


Have you looked at Quick search, limited to a C++ function all the techniques presented in this discussion shall apply to your question. I'm not sure my solution is checking the cursor is within a function definition.

To check for improper uses, you have to define a function. There, first record the current line, and then check the first and last line you detect do surround the initial line. If not, throw an error or do whatever you wish.

EDIT: For instance something like:

" ftplugin/r.vim
onoremap <buffer> <silent> if :<c-u>call <sid>Select_current_function()<cr>
xnoremap <buffer> <silent> if :<c-u>call <sid>Select_current_function()<cr><esc>gv

function! s:Select_current_function() abort
  if 0
    " V1 that doesn't work well when the cursor is on the function declaration
    " The regex needs to be fixed
    let lin = line('.')
    let start = searchpos('<-\s*function\s*(.\{-})\s*{', 'bcenWz') " may depend on your vim version
    if start[0] == 0 
      throw "Not within a function"
    call assert_true(start[0] <= lin) " may not exist with old vim versions
    let end = searchpairpos('{', '', '}', 'nc')
    if end[0] == 0 || end[0] < lin
      throw "Not within a function"
    call cursor(start)
    normal! v
    call cursor(end)

    " or, V2 that supposes that function end is always 0 indented
    " I don't know if this is valid for R
    let p = getcurpos()
    normal! ][
    if getline('.')[col('.')-1] != '}'
      call setpos('.', p)
      throw "Not within a function 1"
    normal! v%
    if line('.') > p[1] 
      call setpos('.', p)
      throw "Not within a function"
  • Thank you for the reply. I tried something similar to what you suggested and it still didn't work. Maybe you can take a quick look - what am I doing wrong? Aug 31, 2016 at 21:49
  • @KarolisKoncevičius I'd have used search() with the don't move the cursor option to search for function start and end. Otherwise, you've forgotten to return something in the second case. BTW, you don't need execute to run silent! normal % Aug 31, 2016 at 22:01
  • I am new to this, as you can probably tell.. Thank you for all the advice. Didn't know about search - that's a good match for what I am doing, will try using it. But not having an "else" inside the function in this case does not seem to be the problem. I verified that the function works otherwise (calin IsInsideFunction() from command line). It just stops working when inside that onoremap Aug 31, 2016 at 22:06
  • @KarolisKoncevičius, the thing is that not all paths of your function return something. You can't use your function result as it may be in an unspecified state. Aug 31, 2016 at 22:34
  • Hmm I really don't think that's the issue. I got this from here Learn Vim Script The Hard Way and it says "if a Vimscript function doesn't return a value, it implicitly returns 0". And I tried adding else - didn't help. Another thing - after restarting vim now the same onoremap is returning 0 everywhere (without changing anything else). Probably something is cached here... Aug 31, 2016 at 22:36

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.