I'm able to get the cursor position with getpos(), but I want to retrieve the selected text within a line, that is '<,'>. How's this done?
UPDATE
I think I edited out the part where I explained that I want to get this text from a Vim script...
I'm able to get the cursor position with getpos(), but I want to retrieve the selected text within a line, that is '<,'>. How's this done?
UPDATE
I think I edited out the part where I explained that I want to get this text from a Vim script...
This is quite an old question, but since I can imagine lots of people will come across it at some point, here's my modified version of @xolox answer
function! VisualSelection()
if mode()=="v"
let [line_start, column_start] = getpos("v")[1:2]
let [line_end, column_end] = getpos(".")[1:2]
else
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
end
if (line2byte(line_start)+column_start) > (line2byte(line_end)+column_end)
let [line_start, column_start, line_end, column_end] =
\ [line_end, column_end, line_start, column_start]
end
let lines = getline(line_start, line_end)
if len(lines) == 0
return ''
endif
let lines[-1] = lines[-1][: column_end - 1]
let lines[0] = lines[0][column_start - 1:]
return join(lines, "\n")
endfunction
'< and '> don't get updated when the user is still in visual mode, thus . and v need to be used in that case.'> comes before '< in the text. In those cases the two positions simply need to be reversed.Assuming the variable "reverse" is defined when the marks are in reverse order:
if exists("reverse")
let lines_r = []
for line in lines
call insert(lines_r, join(reverse(split(line, ".\\zs"))))
endfor
return join(lines_r, "\n")
else
return join(lines, "\n")
end
Added block selection to @xolox's great answer:
mode() isnt used cause it this is planned to be used in function whereby the selection has been cleared by calling the operator etc.
xnoremap <leader>a :<C-U> call GetVisualSelection(visualmode())<Cr>
function! GetVisualSelection(mode)
" call with visualmode() as the argument
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
let lines = getline(line_start, line_end)
if a:mode ==# 'v'
" Must trim the end before the start, the beginning will shift left.
let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)]
let lines[0] = lines[0][column_start - 1:]
elseif a:mode ==# 'V'
" Line mode no need to trim start or end
elseif a:mode == "\<c-v>"
" Block mode, trim every line
let new_lines = []
let i = 0
for line in lines
let lines[i] = line[column_start - 1: column_end - (&selection == 'inclusive' ? 1 : 2)]
let i = i + 1
endfor
else
return ''
endif
for line in lines
echom line
endfor
return join(lines, "\n")
endfunction
Modified version of @DarkWiiPlayer answer.
The differences are:
1.
It test &selection to give the proper functionality when
:behave mswin
As well as the default:
:behave xterm
2.
It also works properly for visual block selections testing visualmode()
I'm also returned the visual selection as an array of lines (becuase that is what I needed). However I've left the return join(lines, "\n") in commented out if you need a signal text block instead.
function! VisualSelection()
if mode()=="v"
let [line_start, column_start] = getpos("v")[1:2]
let [line_end, column_end] = getpos(".")[1:2]
else
let [line_start, column_start] = getpos("'<")[1:2]
let [line_end, column_end] = getpos("'>")[1:2]
end
if (line2byte(line_start)+column_start) > (line2byte(line_end)+column_end)
let [line_start, column_start, line_end, column_end] =
\ [line_end, column_end, line_start, column_start]
end
let lines = getline(line_start, line_end)
if len(lines) == 0
return ['']
endif
if &selection ==# "exclusive"
let column_end -= 1 "Needed to remove the last character to make it match the visual selction
endif
if visualmode() ==# "\<C-V>"
for idx in range(len(lines))
let lines[idx] = lines[idx][: column_end - 1]
let lines[idx] = lines[idx][column_start - 1:]
endfor
else
let lines[-1] = lines[-1][: column_end - 1]
let lines[ 0] = lines[ 0][column_start - 1:]
endif
return lines "use this return if you want an array of text lines
"return join(lines, "\n") "use this return instead if you need a text block
endfunction