Reputation: 20015
I want a movement to jump to the end of a block of code. I wrote a function and I'm trying to onoremap it, but it doesn't work. Here is what I do:
onoremap <silent> } :set opfunc=MovementToEdgeOfBlock(1)<cr>g@
If I do simply:
nnoremap <silent> } :call MovementToEdgeOfBlock(1)<cr>
then the function works as intended. But I need it more as a movement for other commands. So what am I doing wrong?
Here is the function itself (I don't think that the problem is in the function, but anyway):
function! MovementToEdgeOfBlock(direction)
let startLine=line(".")
function! HowManyTabs(line)
let i=0
while a:line[i]==#"\t"
let i+=1
endwhile
return i
endfunction
let startLineTabs = HowManyTabs(getline("."))
echom startLineTabs " tabs"
if a:direction==1
let tabs=HowManyTabs(getline(line('.')+1))
else
let tabs=HowManyTabs(getline(line('.')-1))
endif
while tabs>startLineTabs
if a:direction==1
execute "normal! j"
else
execute "normal! k"
endif
let tabs=HowManyTabs(getline(line('.')))
endwhile
endfunction
Upvotes: 1
Views: 76
Reputation: 53604
Have you read :h 'opfunc'
carefully, including :h g@
which is referenced there? It has absolutely nothing to do with what you want to achieve. More, g@
was never intended to work in operator-pending mode. And more, 'opfunc'
option takes a function name, not an expression like you try to pass it, and passes this function one string argument.
What you should have done is first trying to create exactly the same mapping for operator-pending mode as you use in normal mode. If this does not work try using <expr>
mappings: I would have wrote your function as following:
" Do not redefine function each time ToEdgeOfBlock is called,
" put the definition in global scope: There is no way to have
" a local function in any case.
" The following does exactly the same thing your one used to do (except
" that I moved getline() here), but faster
function! s:HowManyTabs(lnr)
return len(matchstr(getline(a:lnr), "^\t*"))
endfunction
function! s:ToEdgeOfBlock(direction)
let startlnr=line('.')
let startlinetabs=s:HowManyTabs(startlnr)
let shift=(a:direction ? 1 : -1)
let nextlnr=startlnr+shift
while s:HowManyTabs(nextlnr)>startlinetabs && 1<=nextlnr && nextlnr<=line('$')
let nextlnr+=shift
endwhile
return nextlnr.'gg'
endfunction
noremap <expr> } <SID>ToEdgeOfBlock(1)
My version also allows you to undo the jump using <C-o>
.
Upvotes: 2