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 everytime 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>: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(exprmappings return value is executed, but you don’t need it, you need only side effects). You can replace the second line withThe 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 addedrangeto the function definition and uselet [firstline, lastline]=sort([a:firstline, a:lastline], 's:NumSort'). But you nevertheless will exit visual mode with:.