EDIT: Added a potentially improved version below.
I am not entirely sure if I understand your question correctly. ThereforeTher
e, I restate my interpretation of your problem before proposing a potential solution below.
function! SoftLineWrapAwareVerticalCenterToMidScreen ()
" Centers the current line vertically on the window. Soft lines
" are centered such that their middle is at the middle of the
" window.
execute "normal zz"
let l:nchars = strlen(getline("."))
let l:width = winwidth(0)
if l:nchars <= l:width
" There is no need to further adjust the centering
return
endif
" The line is longer than the window width, so we need to
" adjust the centering. We calculate the number of soft lines
" of the current line based on the number of characters in the
" line and the window width.
let l:nsoftlines = nchars / l:width
" In order to adjust the centering, first we need to calculate
" what the soft line is to which the window was centered.
let l:midSoftline = l:nsoftlines / 2
let l:midSoftline = l:midSoftline + 1
" Now we need to calculate the soft line at which the cursor is.
" This is the line with respect to which we want to center the
" window.
let l:cursorPosV = col(".")
let l:cursorSoftline = col(".") / l:width
let l:cursorSoftline = l:cursorSoftline + 1
" The difference between the soft line at which the cursor is
" and the middle soft line is the number of soft lines we need
" to move the window in order to center the cursor.
let l:softlineDiff = l:midSoftline - l:cursorSoftline
" If the difference is positive, then the cursor is above the
" middle of the window, so we need to move the window up.
" Otherwise, we need to move the window down.
if l:softlineDiff > 0
while l:softlineDiff > 0
" Simulate pressing <C-y> to move the window up
call feedkeys("\<C-y>")
let l:softlineDiff = l:softlineDiff - 1
endwhile
else
let l:softlineDiff = -l:softlineDiff
while l:softlineDiff > 0
" Simulate pressing <C-e> to move the window
" down
call feedkeys("\<C-e>")
let l:softlineDiff = l:softlineDiff - 1
endwhile
endif
endfunction
map szz :call SoftLineWrapAwareVerticalCenterToMidScreen()<CR>
Following up on @TheGiwi comment, I came up with the following simpler solution. I believe the solution to be more stable. However, it still struggles with soft wrapped lines that cross the screen boundaries.
function! SoftlineWrapAwareVerticalCenterToMidScreen2 ()
" Get number of lines of the current window:
let l:winHeight = winheight(0)
" Get the line number of the cursor in the current window:
let l:cursorLine = winline()
" Middle line of the window:
let l:midLine = l:winHeight / 2
" Difference between the middle line of the window and the line:
let l:lineDiff = l:midLine - l:cursorLine
" If the difference is positive, then the cursor is above the
" middle of the window, so we need to move the window up.
" Otherwise, we need to move the window down.
if l:lineDiff > 0
while l:lineDiff > 0
" Simulate pressing <C-y> to move the window up
call feedkeys("\<C-y>")
let l:lineDiff = l:lineDiff - 1
endwhile
else
let l:lineDiff = -l:lineDiff
while l:lineDiff > 0
" Simulate pressing <C-e> to move the window down
call feedkeys("\<C-e>")
let l:lineDiff = l:lineDiff - 1
endwhile
endif
endfunction
" Added <leader> because I personally did not want to remap my `j` and `k` keys at any time.
map <leader>j gjszz
map <leader>k gkszz
``