开发者

Get the current line in visual mode from a function

I have a simple vim script that takes a visual block of text and stores it as a list. The problem with the function VtoList() is that it executes after the cursor returns to the start of the visual block, not before it. Because of this, I have no way of getting the line where the visual block ends.

nn <F2> :call VtoList()<CR>

func! VtoList()
    firstline = line('v')  " Gets the line where the visual block begins
    lastline = line('.')   " Gets the current line, but not the one I want.
    mylist = getline(firstline, lastline)
    echo mylist
endfunc

The problem is with line('.'). It should return the current line of the cursor, but before the function is called, the cursor has already returned to the start of the visual block. Thus, I'm only getting a single line instead of a range of lines.

I put together a solution that sets a mark every开发者_运维技巧time the user hits V and sets another mark before the function is called.

nnoremap V mV
nnoremap <F2> mZ:call VtoList()<CR>

The function works fine if I substitute line('v') and line('.') with line("'V") and line("'Z"), but I want to avoid this solution if I can because it could conflict with a user's mappings.

Is there a way I can get current line of a visual block within a function before the cursor has returned to the start of the visual block?


Don't use :, use <expr>:

function! s:NumSort(a, b)
    return a:a>a:b ? 1 : a:a==a:b ? 0 : -1
endfunction
func! VtoList()
    let [firstline, lastline]=sort([line('v'), line('.')], 's:NumSort')
    let mylist = getline(firstline, lastline)
    echo mylist
    return ""
endfunc
vnoremap <expr> <F2> VtoList()

Note other changes: let (you forgot it), sort (line where selection starts may be after the line where selection ends), vnoremap (line("v") works only in visual mode), return (expr mappings return value is executed, but you don't need it, you need only side effects). You can replace the second line with

    if mode()=~#"^[vV\<C-v>]"
        let [firstline, lastline]=sort([line('v'), line('.')], 's:NumSort')
    else
        let [firstline, lastline]=sort([line("'<"), line("'>")], 's:NumSort')
    endif

The reason why your solution is not working is that when : occurs in the mapping, you immediately exit visual mode and enter command mode. line("v") works only in visual mode.

Other note: vnoremap {lhs} : will produce command line already filled with '<,'>. You may have added range to the function definition and use let [firstline, lastline]=sort([a:firstline, a:lastline], 's:NumSort'). But you nevertheless will exit visual mode with :.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜