It is not always possible to achieve the desired output since the first window row is always the start of a line (if smoothscroll
is not set)
Suppose you have that text (with cursor at row 2):
2 line 2 foo bar tom foo bar tom foo
>3 line 3 foo bar tom foo bar tom foo
4 line 4 foo bar tom foo bar tom foo
When you toggle wrap:
You can have (with cursor at row 3):
2 line 2 foo bar tom
foo bar tom foo
>3 line 3 foo bar tom
foo bar tom foo
4 line 4 foo bar tom
foo bar tom foo
or (with cursor at row 1):
>3 line 3 foo bar tom
foo bar tom foo
4 line 4 foo bar tom
foo bar tom foo
But not (with cursor at row 2 as you which):
foo bar tom foo
>3 line 3 foo bar tom
foo bar tom foo
4 line 4 foo bar tom
foo bar tom foo
Another limitation is that the start of the text is always at row 1
Suppose you start with (cursor at row 6)
2 line 2 foo bar tom
foo bar tom foo
3 line 3 foo bar tom
foo bar tom foo
4 line 4 foo bar tom
> foo bar tom foo
When you toggle wrap the best you can have is (with cursor at row 4):
1 line 1 foo bar tom foo bar tom foo
2 line 2 foo bar tom foo bar tom foo
3 line 3 foo bar tom foo bar tom foo
>4 line 4 foo bar tom foo bar tom foo
That being said here is an approximation of what you would like to have:
function GetWinWidth()
let ret = winwidth(0)
if &signcolumn !=# 'no'
let ret = ret - 2
endif
if &number
let ret = ret - max([&numberwidth, float2nr(log10(line('$'))) + 2])
endif
return ret
endfunction
function WrapRowDelta(line1, line2)
" This is an approximation that could be improved :-)
let ret = 0
let max_width = GetWinWidth()
for i in range(a:line1, a:line2 - 1)
if foldclosed(i) < 0
let ret = ret + float2nr(ceil(str2float(len(getline(i)) + 1) / max_width))
elseif foldclosed(i) == i
let ret = ret + 1
endif
endfor
return ret
endfunction
function! NoWrapRowDelta(line1, line2)
" return a:line2 - a:line1
let ret = 0
for i in range(a:line1, a:line2 - 1)
if foldclosed(i) < 0
let ret = ret + 1
elseif foldclosed(i) == i
let ret = ret + 1
endif
endfor
return ret
endfunction
function! CorrectCursorScroll()
if &wrap
" Estimation of the previous space:
let nonwrap_row_delta = NoWrapRowDelta(line('w0'), line('.'))
" Value of the current space
let wrap_row_delta = screenpos(0, line('.'), col('.')).row - 1
while wrap_row_delta > nonwrap_row_delta
exe "normal! \<C-e>"
let r = screenpos(0, line('.'), col('.')).row - 1
if wrap_row_delta == r
break
endif
let wrap_row_delta = r
endwhile
if wrap_row_delta < nonwrap_row_delta
exe "normal! \<C-y>"
endif
else
" Estimation of the previous space:
let wrap_row_delta = WrapRowDelta(line('w0'), line('.'))
" Value of the current space
let nonwrap_row_delta = NoWrapRowDelta(line('w0'), line('.'))
while wrap_row_delta > nonwrap_row_delta
exe "normal! \<C-y>"
let r = NoWrapRowDelta(line('w0'), line('.'))
if nonwrap_row_delta == r
break
endif
let nonwrap_row_delta = r
endwhile
if wrap_row_delta < nonwrap_row_delta
exe "normal! \<C-e>"
endif
endif
endfunction
autocmd! OptionSet wrap call CorrectCursorScroll()
'smoothscroll'
set?