Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Are there any vim functions, similar to getline(), that can access the current display line of a wrapped line of text in a buffer? Alternatively, are there any functions similar to col(), getpos() or getcurpos() that I could use to return the start/end column of the current display/screen line, from within a script?

I realize I could move the cursor around with g0 and g$, and then get positions after such moves. However, I'm specifically looking for a built-in or custom function that does NOT move the cursor. This is being used in a complex operator-pending mapping, so it's best for the cursor to stay put.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
217 views
Welcome To Ask or Share your Answers For Others

1 Answer

After some tinkering, this seemed to be the best available method for finding the bounds of the current screen line, in the absence of other answers. Alas, it does move the cursor, but restores its original position. The function returns a list of the beginning-of-line and end-of-line column indices, like [1, 25].

function! DispLineCols()
  "display line columns:  [bol, eol] columns for current screen line
  let r = []
  let p = getcurpos()
  normal! g0
  call add(r, col('.'))
  normal! g$
  call add(r, col('.'))
  call setpos('.', p)
  return r
endfunction

I wrote the following function to return a list of lists (in the same [bol, eol] format indicated above) for all screen lines that the current wrapped line comprises. For example, for a wrapped line that comprises three screen lines, this might return: [[1, 79], [80, 159], [160, 180]]

function! DispLinesCols()
  "display lines columns:  [[bol1, eol1], [bol2, eol2], ...] columns for
  "  all screen line wraps of current line
  let r = []
  let p = getcurpos()
  normal! 0
  call add(r, DispLineCols())
  normal! g$l
  while col('.') != r[-1][1]
    call add(r, DispLineCols())
    normal! g$l
  endwhile
  call setpos('.', p)
  return r
endfunction

Not a perfect (or even elegant) solution, but gets the bounds of the display/screen line well enough. Still looking for better solutions...

EDIT: For completeness, here are two functions that will turn the column [bol, eol] output from the functions above into the actual text of the lines.

function! DispLineText()
  "display line text:  the text on the current screen line
  let [beg, end] = DispLineCols()
  return getline('.')[beg-1 : end-1]
endfunction

function! DispLinesText()
  "display lines text:  list of screen lines comprising the current line
  let r = []
  let l = getline('.')
  for [beg, end] in DispLinesCols()
    call add(r, l[beg-1 : end-1])
  endfor
  return r
endfunction

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...