需要一些帮助来编写自定义运动

时间:2012-10-04 19:22:41

标签: vim

我希望一个动作跳转到一段代码的末尾。我写了一个函数,我正在尝试onoremap它,但它不起作用。这是我的工作:

onoremap <silent> } :set opfunc=MovementToEdgeOfBlock(1)<cr>g@

如果我这样做:

nnoremap <silent> } :call MovementToEdgeOfBlock(1)<cr>

然后该功能按预期工作。但我更需要它作为其他命令的运动。那么我做错了什么?

这是函数本身(我不认为问题出在函数中,但无论如何):

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

1 个答案:

答案 0 :(得分:2)

您是否仔细阅读了:h 'opfunc',包括在此引用的:h g@?它与你想要达到的目标完全无关。此外,g@从未打算在运营商挂起模式下工作。而且,'opfunc'选项采用函数名称,而不是像尝试传递它的表达式,并将此函数传递给一个字符串参数。

您应该做的是首先尝试为正常模式下的操作员待定模式创建完全相同的映射。如果这不起作用,请尝试使用<expr>映射:我会将您的函数编写如下:

" 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)

我的版本还允许您使用<C-o>撤消跳转。