5

Now if I select something in visual mode, is there some way to get the selected area without having to yank it to some register?

I looked through :h functions but didn't find anything.

1
  • 4
    It could look like a silly question but: what are you trying to do? to get the selected area without having to yank it to some register, does it mean finding its position in the buffer with '< and '>, re-selecting it visually, or something else? And why? What is your final objective?
    – statox
    Jun 13, 2016 at 7:48

3 Answers 3

6

If you really want to avoid the registers, you can use the visual marks to figure out byte positions of the selected text:

function! s:pos2byte(pos) abort
    return line2byte(a:pos[1]) + a:pos[2]
endfunction

function! s:get_visual_text() abort
    let b1 = s:pos2byte(getpos("'<"))
    let b2 = s:pos2byte(getpos("'>"))
    let text = ''

    while b1 < b2
        let l = byte2line(b1)
        let lb = line2byte(l)
        let line = strpart(getline(l), b1 - lb - 1)
        let text .= line
        let b1 += len(line)
    endwhile

    return strpart(text, 0, len(text) - (b1 - b2) + 1)
endfunction

It works well enough, but there's something about it that I don't trust. I think it might need more checks to make sure an infinite loops doesn't happen, and it won't work on visual blocks.

I prefer using the temporary register method because I don't have to think too hard about what's going to happen. This is the proper way to do it if you want to leave the buffer state undisturbed:

function! s:get_visual_text() abort
    " Save the window's view because `gv` may change the scroll position.
    let view = winsaveview()

    " Preserve the yank/change marks
    let m1 = getpos("'[")
    let m2 = getpos("']")

    " Preserve the 'a' register, as well as what kind of register it is.
    let reg_val = getreg('a')
    let reg_type = getregtype('a')

    " Yank text into the 'a' register and get the text
    normal! gv"ay
    let text = getreg('a')

    " Restore the 'a' register
    call setreg('a', reg_val, reg_type)

    " Restore the yank/change marks
    call setpos("'[", m1)
    call setpos("']", m2)

    " Restore the window's view
    call winrestview(view)

    return text
endfunction
1
  • 2
    Using strpart is likely to not work with utf-8 characters. Jun 13, 2016 at 9:47
5

There is no other way but to yank it into a register. At best, you can restore the register once you're done.

For instance, I have the following utility function that cleans behind itself:

function! lh#visual#selection()
  try
    let a_save = @a
    normal! gv"ay
    return @a
  finally
    let @a = a_save
  endtry
endfunction

(Note I know this question has been asked a few time on SO, but I'm not sure about vi.SE)

2
  • 1
    Why would this need a try statement?
    – hgiesel
    Jun 12, 2016 at 23:30
  • 2
    @hgiesel Good question. I'd say it's an old habit -- and an old code (IOW, I don't remember why I did that). May be it makes a difference if the function is called when vim has just started and nothing have ever been selected. I'll have to check. It's more defensive programming than any else here. Jun 13, 2016 at 8:11
2

There is a way to select the previously selected visual area.

If you have selected some text through v, V, or Ctrl+v, you can reselect the portion by pressing gv in normal mode. (You can reselect it irrespective of whether you did any operation or cancelled the selection)

Functions accept line range and marks as well. You can use your functions with visual marks like :'<,'>function(). This will apply the function within the recently selected visual range. Or, you can select the text through any of the visual modes and cancel selection and then use this in your function by executing gv inside the function, like :execute 'gv'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.